diff --git a/CHANGELOG.mkdn b/CHANGELOG.mkdn deleted file mode 100644 index 5f2dce4..0000000 --- a/CHANGELOG.mkdn +++ /dev/null @@ -1,167 +0,0 @@ -Pesterchum 3.41 -=============== - -Visit http://nova.xzibition.com/~illuminatedwax/help.html for tutorial. - -**Stable**: Visit https://github.com/illuminatedwax/pesterchum for git access and source code. - -**Bleeding Edge**: Visit https://github.com/kiooeht/pesterchum for git access and source code. - -**Mac**: For Mac specific git access and source code visit https://github.com/Lexicality/pesterchum. - -(Note: Bleeding Edge is up-to-date with all Mac specific changes.) - -CHANGELOG ---------- -## 3.41.4 -* Makefile for Linux installing - Kiooeht [evacipatedBox] -* Recognize www. as link - Kiooeht [evacipatedBox] -* Pester menu option to just pester a handle - Kiooeht [evacipatedBox] -* Update to randomEncounter interface - Kiooeht [evacipatedBox] -* Italics, bold, and underline - Kiooeht [evacipatedBox] -* FTP and Magnet links - oakwhiz -* Userlist search - oakwhiz -* Chanserv in menus - Cerxi [binaryCabalist] -* Lua quirks -* Multi-select memo chooser - [alGore] -* Auto-identify with NickServ - Kiooeht [evacipatedBox] -* Auto-join memos - Kiooeht [evacipatedBox] -* Bug fixes - * Don't require pygame (it's kind of optional, you just don't get sound) - Kiooeht [evacipatedBox] - * Allow add chum dialog to open after adding an existing chum - Kiooeht [evacipatedBox] - * Unicode everything - ghostDunk - * Delete groups when using online numbers - Kiooeht [evacipatedBox] - * Add chums when using manual sorting - Kiooeht [evacipatedBox] - * Memo case insensitive for userlist and modes - Kiooeht [evacipatedBox] - * Move hidden chums when deleting group - Kiooeht [evacipatedBox] - * Don't allow rename groups with parenthesis - Kiooeht [evacipatedBox] - * Wrap long error messages - Kiooeht [evacipatedBox] - * chdir into quirks folder for Lua quirks - [alGore] - * Toast notifications don't require sound to be on - Kiooeht [evacipatedBox] - * Don't close Pesterchum if a window is closed while main window minimized - Kiooeht [evacipatedBox] - - -### 3.41.3 -* Add group option when adding chum - ghostDunk -* OOC Mode - ghostDunk -* Improve animated gifs - ghostDunk -* Set IRC away on idle - Kiooeht [evacipatedBox] -* Remote quirk shutoff in memos - Kiooeht [evacipatedBox] -* Compress exit dumps into one line - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* Display channel mode change message - Kiooeht [evacipatedBox] -* Disable quirks in +c memos - Lexi [lexicalNuance] -* Founder, admin, and halfop support - Kiooeht [evacipatedBox] -* Button for direct access to logs directory - Kiooeht [evacipatedBox] -* Auto-update from zip and tar - Kiooeht [evacipatedBox] -* Minimizable memo userlist - Kiooeht [evacipatedBox] (Idea: [alGore], [lostGash]) -* Chumroll notifications on chum sign-in/out - Kiooeht [evacipatedBox] -* Chum notes - Kiooeht [evacipatedBox] -* Customizable name alerts - Kiooeht [evacipatedBox] -* Update bug reporter - Kiooeht [evacipatedBox] -* Explain why a chumhandle is invalid - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* Netsplit notification in memos - Kiooeht [evacipatedBox] -* Toast Notifications - Kiooeht [evacipatedBox] -* Disable randomEncounter options when it's offline - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* Sort list of memos alphabetically or by number of users - Kiooeht [evacipatedBox] (Idea: [lostGash]) -* Low-bandwidth mode - Kiooeht [evacipatedBox] (Idea: [canLover]) -* New smilies - Kiooeht [evacipatedBox] -* Refresh theme in options - Kiooeht [evacipatedBox] -* Separate tabbed/untabbed windows for conversaions and memos - Kiooeht [evacipatedBox] -* Manually rearrange chumroll - Kiooeht [evacipatedBox] (Idea: [turntableAbbess (aka. TA of SGRILL)]) -* Using user data directory for all OSs - Kiooeht [evacipatedBox] -* Lots more user created themes - ghostDunk -* Bug fixes - * Don't delete random chum when blocking someone not on chumroll - Kiooeht [evacipatedBox] - * Openning global userlist doesn't reset OP status of memo users - Kiooeht [evacipatedBox] - * Alt characters don't break on random replace - Kiooeht [evacipatedBox] - * Trollian 2.5 tray icon is now Trollian icon - Kiooeht [evacipatedBox] - * Don't screw up tags with the mispeller - Kiooeht [evacipatedBox] - * Don't break if profile uses non-existant theme - Kiooeht [evacipatedBox] - * Properly rearrange groups when not displaying number of online chums - Kiooeht [evacipatedBox] -* Mac Bug fixes - * Create all datadir stuff - Lexi [lexicalNuance] - -### 3.41 -* Individually turn quirks on and off - Kiooeht [evacipatedBox] -* More canon trollian theme timeline indicators - [binaryCabalist] -* By mood chum sorting - Kiooeht [evacipatedBox] -* Chum groups - Kiooeht [evacipatedBox] -* Turn logging on and off - Kiooeht [evacipatedBox] -* Customizable idle time - Kiooeht [evacipatedBox] -* Different sound for memos - Kiooeht [evacipatedBox] -* Animated smilies - Kiooeht [evacipatedBox] -* Delete profiles - Kiooeht [evacipatedBox] -* Customize minimize and close button actions - Kiooeht [evacipatedBox] -* Receive notices from services you're talking to - Kiooeht [evacipatedBox] -* Automatically turn off quirks when talking to bots - Kiooeht [evacipatedBox] -* Rearrange options menu, make tabbed - Kiooeht [evacipatedBox] -* Rearrange memos window for readability - Kiooeht [evacipatedBox] -* Give voice to memo users - Kiooeht [evacipatedBox] -* Theme checking - Kiooeht [evacipatedBox] -* Display (De)OP/Voice messages in memos - Kiooeht [evacipatedBox] -* Advanced Mode: Alter IRC user mode - Kiooeht [evacipatedBox] -* Logviewer chum search - Kiooeht [evacipatedBox] -* Logviewer log search - Kiooeht [evacipatedBox] -* Set server and port from command line - Kiooeht [evacipatedBox] -* Invite-only memos, invite chums to memos - Kiooeht [evacipatedBox] -* Check Pyqt4 and pygame are installed and correct versions - Kiooeht [evacipatedBox] -* Advanced Mode: View memo (channel) modes - Kiooeht [evacipatedBox] -* Quirk groups - Kiooeht [evacipatedBox] -* CTCP Version reply - Kiooeht [evacipatedBox] -* Check for Pesterchum updates - Kiooeht [evacipatedBox] -* Memo OP options: Secret, Invite-only, Mute - Kiooeht [evacipatedBox] -* Notify user if channel blocks message - Kiooeht [evacipatedBox] -* Bug reporter - Kiooeht [evacipatedBox] -* Python quirks (users can create own quirk functions) - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* Incorporate support for the new randomEncounter - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* Only GETMOOD for people online (less spam!) - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* Quirk tester in quirk window - Kiooeht [evacipatedBox] (Idea: [alGore]) -* Show and support giving kick reasons - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* Make adding quirks into multi-page wizard - Kiooeht [evacipatedBox] -* Flash the taskbar on new messages - Kiooeht [evacipatedBox] -* Third beep sound for when your initials are mentioned in memos - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* Ctrl + click to copy links - Kiooeht [evacipatedBox] -* Say something when server is full - Kiooeht [evacipatedBox] -* Ping server if no ping from server to test connection - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance]) -* MSPA comic update notifier - Kiooeht [evacipatedBox] -* Volume control - Kiooeht [evacipatedBox] -* Debug mode - illuminatedwax [ghostDunk] -* Bug fixes - * Logviewer updates - Kiooeht [evacipatedBox] - * Memo scrollbar thing - Kiooeht [evacipatedBox] - * Time arrows in enamel - Kiooeht [evacipatedBox] - * Quirk order actually works - Kiooeht [evacipatedBox] - * Stay in memos on profile switch - Kiooeht [evacipatedBox] - * Auto rejoin memos on reconnect - Kiooeht [evacipatedBox] - * De-Op in memos correctly - Kiooeht [evacipatedBox] - * Don't blow up if someone's not using Pesterchum in a memo - Kiooeht [evacipatedBox] - * Make 'logs' and 'profiles' directories if non-existant - Kiooeht [evacipatedBox] - * Don't split messages in bad places - Kiooeht [evacipatedBox] - * Chumhandles must match EXACTLY to register mood changes - Kiooeht [evacipatedBox] - * Menu bar text colour correct when default system colour isn't black - Kiooeht [evacipatedBox] - * End all colour tags and restart them on split messages - Kiooeht [evacipatedBox] - * Chat input box right-click menus - Kiooeht [evacipatedBox] - * Don't overflow random colours into colourless messages - Kiooeht [evacipatedBox] - * Only open links on left click - Kiooeht [evacipatedBox] - -### 3.14.1 -* Pesterchum 3.14 - illuminatedwax [ghostDunk] -* Art - Grimlive [aquaMarinist] -* Quirks lower() function - Kiooeht [evacipatedBox] -* Quirks scrabble() function - Kiooeht [evacipatedBox] -* Quirks reverse() function - illuminatedwax [ghostDunk] -* Timestamps - Kiooeht [evacipatedBox] -* Logviewer - Kiooeht [evacipatedBox] -* Quirk ordering - [alGore] -* # of users in a memo - [alGore] -* @links to users - illuminatedwax [ghostDunk] -* Support for REPORT and ALT to calSprite built in - illuminatedwax [ghostDunk] -* Bug fixes: - * mixer bug fixed - * "flags" bug fixed - * incorrect characters in memos no longer break log file names - * memos now do not break on case-sensitivity - * fixed QDB address - * now lines too long to send in a single message are split up correctly - * quirk replace bug fixed - * pesterClientXXX profiles no longer saved diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 7a4ed15..0000000 --- a/INSTALL +++ /dev/null @@ -1,28 +0,0 @@ -There is no installing. - -Basically this is a mishmosh of source code that will run by invoking: - -python pesterchum.py - -You will need these libraries: -PyQt >= 4.6 (implies Qt 4.6!) -pygame - -The setup files are all broken. If you are building on Mac, Archaemic -has been kind enough to give us a head start in the setup-py2app.py -and py2app.sh files. Check out the MACBUILD file for his comments. - -If you are building on Windows, the setup.py file has some -commented-out lines that should give you a clue as to what you need to -do. Talk to me if you reeeeally want to build on Windows. - -On Linux, you need to have the PyQt4 and pygame libraries installed: - -Debian: apt-get install python-qt4 python-pgame -Arch: pacman -S pyqt4 python-pygame - -then run ./pesterchum (basically a shell script that runs python pesterchum.py) - -The point of all this is that the only person besides myself that I -expect to create builds are the awesome people that volunteer to help -me build on a Mac. \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 4f0c389..0000000 --- a/LICENSE +++ /dev/null @@ -1,687 +0,0 @@ - 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 . - - 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/MacBuild/GPL.res b/MacBuild/GPL.res deleted file mode 100644 index 447c37b..0000000 --- a/MacBuild/GPL.res +++ /dev/null @@ -1,1151 +0,0 @@ -data 'STR#' (5000, "English") { - $"0006 0745 6E67 6C69 7368 0541 6772 6565" /* ...English.Agree */ - $"0844 6973 6167 7265 6505 5072 696E 7407" /* .Disagree.Print. */ - $"5361 7665 2E2E 2E79 4966 2079 6F75 2061" /* Save...yIf you a */ - $"6772 6565 2077 6974 6820 7468 6520 7465" /* gree with the te */ - $"726D 7320 6F66 2074 6869 7320 6C69 6365" /* rms of this lice */ - $"6E73 652C 2063 6C69 636B 2022 4167 7265" /* nse, click "Agre */ - $"6522 2074 6F20 6163 6365 7373 2074 6865" /* e" to access the */ - $"2073 6F66 7477 6172 652E 2049 6620 796F" /* software. If yo */ - $"7520 646F 206E 6F74 2061 6772 6565 2C20" /* u do not agree, */ - $"7072 6573 7320 2244 6973 6167 7265 6522" /* press "Disagree" */ - $"2E" /* . */ -}; - -data 'TEXT' (5000, "English") { - $"0909 2020 2020 474E 5520 4745 4E45 5241" /* ÆÆ GNU GENERA */ - $"4C20 5055 424C 4943 204C 4943 454E 5345" /* L PUBLIC LICENSE */ - $"0D09 0920 2020 2020 2020 5665 7273 696F" /* .ÆÆ Versio */ - $"6E20 322C 204A 756E 6520 3139 3931 0D0D" /* n 2, June 1991.. */ - $"2043 6F70 7972 6967 6874 2028 4329 2031" /* Copyright (C) 1 */ - $"3938 392C 2031 3939 3120 4672 6565 2053" /* 989, 1991 Free S */ - $"6F66 7477 6172 6520 466F 756E 6461 7469" /* oftware Foundati */ - $"6F6E 2C20 496E 632E 0D20 2020 2020 2020" /* on, Inc.. */ - $"2020 2020 2020 2020 2020 2020 2020 2020" /* */ - $"3539 2054 656D 706C 6520 506C 6163 652C" /* 59 Temple Place, */ - $"2053 7569 7465 2033 3330 2C20 426F 7374" /* Suite 330, Bost */ - $"6F6E 2C20 4D41 2020 3032 3131 312D 3133" /* on, MA 02111-13 */ - $"3037 2020 5553 410D 2045 7665 7279 6F6E" /* 07 USA. Everyon */ - $"6520 6973 2070 6572 6D69 7474 6564 2074" /* e is permitted t */ - $"6F20 636F 7079 2061 6E64 2064 6973 7472" /* o copy and distr */ - $"6962 7574 6520 7665 7262 6174 696D 2063" /* ibute verbatim c */ - $"6F70 6965 730D 206F 6620 7468 6973 206C" /* opies. of this l */ - $"6963 656E 7365 2064 6F63 756D 656E 742C" /* icense document, */ - $"2062 7574 2063 6861 6E67 696E 6720 6974" /* but changing it */ - $"2069 7320 6E6F 7420 616C 6C6F 7765 642E" /* is not allowed. */ - $"0D0D 0909 0920 2020 2050 7265 616D 626C" /* ..ÆÆÆ Preambl */ - $"650D 0D20 2054 6865 206C 6963 656E 7365" /* e.. The license */ - $"7320 666F 7220 6D6F 7374 2073 6F66 7477" /* s for most softw */ - $"6172 6520 6172 6520 6465 7369 676E 6564" /* are are designed */ - $"2074 6F20 7461 6B65 2061 7761 7920 796F" /* to take away yo */ - $"7572 0D66 7265 6564 6F6D 2074 6F20 7368" /* ur.freedom to sh */ - $"6172 6520 616E 6420 6368 616E 6765 2069" /* are and change i */ - $"742E 2020 4279 2063 6F6E 7472 6173 742C" /* t. By contrast, */ - $"2074 6865 2047 4E55 2047 656E 6572 616C" /* the GNU General */ - $"2050 7562 6C69 630D 4C69 6365 6E73 6520" /* Public.License */ - $"6973 2069 6E74 656E 6465 6420 746F 2067" /* is intended to g */ - $"7561 7261 6E74 6565 2079 6F75 7220 6672" /* uarantee your fr */ - $"6565 646F 6D20 746F 2073 6861 7265 2061" /* eedom to share a */ - $"6E64 2063 6861 6E67 6520 6672 6565 0D73" /* nd change free.s */ - $"6F66 7477 6172 652D 2D74 6F20 6D61 6B65" /* oftware--to make */ - $"2073 7572 6520 7468 6520 736F 6674 7761" /* sure the softwa */ - $"7265 2069 7320 6672 6565 2066 6F72 2061" /* re is free for a */ - $"6C6C 2069 7473 2075 7365 7273 2E20 2054" /* ll its users. T */ - $"6869 730D 4765 6E65 7261 6C20 5075 626C" /* his.General Publ */ - $"6963 204C 6963 656E 7365 2061 7070 6C69" /* ic License appli */ - $"6573 2074 6F20 6D6F 7374 206F 6620 7468" /* es to most of th */ - $"6520 4672 6565 2053 6F66 7477 6172 650D" /* e Free Software. */ - $"466F 756E 6461 7469 6F6E 2773 2073 6F66" /* Foundation's sof */ - $"7477 6172 6520 616E 6420 746F 2061 6E79" /* tware and to any */ - $"206F 7468 6572 2070 726F 6772 616D 2077" /* other program w */ - $"686F 7365 2061 7574 686F 7273 2063 6F6D" /* hose authors com */ - $"6D69 7420 746F 0D75 7369 6E67 2069 742E" /* mit to.using it. */ - $"2020 2853 6F6D 6520 6F74 6865 7220 4672" /* (Some other Fr */ - $"6565 2053 6F66 7477 6172 6520 466F 756E" /* ee Software Foun */ - $"6461 7469 6F6E 2073 6F66 7477 6172 6520" /* dation software */ - $"6973 2063 6F76 6572 6564 2062 790D 7468" /* is covered by.th */ - $"6520 474E 5520 4C69 6272 6172 7920 4765" /* e GNU Library Ge */ - $"6E65 7261 6C20 5075 626C 6963 204C 6963" /* neral Public Lic */ - $"656E 7365 2069 6E73 7465 6164 2E29 2020" /* ense instead.) */ - $"596F 7520 6361 6E20 6170 706C 7920 6974" /* You can apply it */ - $"2074 6F0D 796F 7572 2070 726F 6772 616D" /* to.your program */ - $"732C 2074 6F6F 2E0D 0D20 2057 6865 6E20" /* s, too... When */ - $"7765 2073 7065 616B 206F 6620 6672 6565" /* we speak of free */ - $"2073 6F66 7477 6172 652C 2077 6520 6172" /* software, we ar */ - $"6520 7265 6665 7272 696E 6720 746F 2066" /* e referring to f */ - $"7265 6564 6F6D 2C20 6E6F 740D 7072 6963" /* reedom, not.pric */ - $"652E 2020 4F75 7220 4765 6E65 7261 6C20" /* e. Our General */ - $"5075 626C 6963 204C 6963 656E 7365 7320" /* Public Licenses */ - $"6172 6520 6465 7369 676E 6564 2074 6F20" /* are designed to */ - $"6D61 6B65 2073 7572 6520 7468 6174 2079" /* make sure that y */ - $"6F75 0D68 6176 6520 7468 6520 6672 6565" /* ou.have the free */ - $"646F 6D20 746F 2064 6973 7472 6962 7574" /* dom to distribut */ - $"6520 636F 7069 6573 206F 6620 6672 6565" /* e copies of free */ - $"2073 6F66 7477 6172 6520 2861 6E64 2063" /* software (and c */ - $"6861 7267 6520 666F 720D 7468 6973 2073" /* harge for.this s */ - $"6572 7669 6365 2069 6620 796F 7520 7769" /* ervice if you wi */ - $"7368 292C 2074 6861 7420 796F 7520 7265" /* sh), that you re */ - $"6365 6976 6520 736F 7572 6365 2063 6F64" /* ceive source cod */ - $"6520 6F72 2063 616E 2067 6574 2069 740D" /* e or can get it. */ - $"6966 2079 6F75 2077 616E 7420 6974 2C20" /* if you want it, */ - $"7468 6174 2079 6F75 2063 616E 2063 6861" /* that you can cha */ - $"6E67 6520 7468 6520 736F 6674 7761 7265" /* nge the software */ - $"206F 7220 7573 6520 7069 6563 6573 206F" /* or use pieces o */ - $"6620 6974 0D69 6E20 6E65 7720 6672 6565" /* f it.in new free */ - $"2070 726F 6772 616D 733B 2061 6E64 2074" /* programs; and t */ - $"6861 7420 796F 7520 6B6E 6F77 2079 6F75" /* hat you know you */ - $"2063 616E 2064 6F20 7468 6573 6520 7468" /* can do these th */ - $"696E 6773 2E0D 0D20 2054 6F20 7072 6F74" /* ings... To prot */ - $"6563 7420 796F 7572 2072 6967 6874 732C" /* ect your rights, */ - $"2077 6520 6E65 6564 2074 6F20 6D61 6B65" /* we need to make */ - $"2072 6573 7472 6963 7469 6F6E 7320 7468" /* restrictions th */ - $"6174 2066 6F72 6269 640D 616E 796F 6E65" /* at forbid.anyone */ - $"2074 6F20 6465 6E79 2079 6F75 2074 6865" /* to deny you the */ - $"7365 2072 6967 6874 7320 6F72 2074 6F20" /* se rights or to */ - $"6173 6B20 796F 7520 746F 2073 7572 7265" /* ask you to surre */ - $"6E64 6572 2074 6865 2072 6967 6874 732E" /* nder the rights. */ - $"0D54 6865 7365 2072 6573 7472 6963 7469" /* .These restricti */ - $"6F6E 7320 7472 616E 736C 6174 6520 746F" /* ons translate to */ - $"2063 6572 7461 696E 2072 6573 706F 6E73" /* certain respons */ - $"6962 696C 6974 6965 7320 666F 7220 796F" /* ibilities for yo */ - $"7520 6966 2079 6F75 0D64 6973 7472 6962" /* u if you.distrib */ - $"7574 6520 636F 7069 6573 206F 6620 7468" /* ute copies of th */ - $"6520 736F 6674 7761 7265 2C20 6F72 2069" /* e software, or i */ - $"6620 796F 7520 6D6F 6469 6679 2069 742E" /* f you modify it. */ - $"0D0D 2020 466F 7220 6578 616D 706C 652C" /* .. For example, */ - $"2069 6620 796F 7520 6469 7374 7269 6275" /* if you distribu */ - $"7465 2063 6F70 6965 7320 6F66 2073 7563" /* te copies of suc */ - $"6820 6120 7072 6F67 7261 6D2C 2077 6865" /* h a program, whe */ - $"7468 6572 0D67 7261 7469 7320 6F72 2066" /* ther.gratis or f */ - $"6F72 2061 2066 6565 2C20 796F 7520 6D75" /* or a fee, you mu */ - $"7374 2067 6976 6520 7468 6520 7265 6369" /* st give the reci */ - $"7069 656E 7473 2061 6C6C 2074 6865 2072" /* pients all the r */ - $"6967 6874 7320 7468 6174 0D79 6F75 2068" /* ights that.you h */ - $"6176 652E 2020 596F 7520 6D75 7374 206D" /* ave. You must m */ - $"616B 6520 7375 7265 2074 6861 7420 7468" /* ake sure that th */ - $"6579 2C20 746F 6F2C 2072 6563 6569 7665" /* ey, too, receive */ - $"206F 7220 6361 6E20 6765 7420 7468 650D" /* or can get the. */ - $"736F 7572 6365 2063 6F64 652E 2020 416E" /* source code. An */ - $"6420 796F 7520 6D75 7374 2073 686F 7720" /* d you must show */ - $"7468 656D 2074 6865 7365 2074 6572 6D73" /* them these terms */ - $"2073 6F20 7468 6579 206B 6E6F 7720 7468" /* so they know th */ - $"6569 720D 7269 6768 7473 2E0D 0D20 2057" /* eir.rights... W */ - $"6520 7072 6F74 6563 7420 796F 7572 2072" /* e protect your r */ - $"6967 6874 7320 7769 7468 2074 776F 2073" /* ights with two s */ - $"7465 7073 3A20 2831 2920 636F 7079 7269" /* teps: (1) copyri */ - $"6768 7420 7468 6520 736F 6674 7761 7265" /* ght the software */ - $"2C20 616E 640D 2832 2920 6F66 6665 7220" /* , and.(2) offer */ - $"796F 7520 7468 6973 206C 6963 656E 7365" /* you this license */ - $"2077 6869 6368 2067 6976 6573 2079 6F75" /* which gives you */ - $"206C 6567 616C 2070 6572 6D69 7373 696F" /* legal permissio */ - $"6E20 746F 2063 6F70 792C 0D64 6973 7472" /* n to copy,.distr */ - $"6962 7574 6520 616E 642F 6F72 206D 6F64" /* ibute and/or mod */ - $"6966 7920 7468 6520 736F 6674 7761 7265" /* ify the software */ - $"2E0D 0D20 2041 6C73 6F2C 2066 6F72 2065" /* ... Also, for e */ - $"6163 6820 6175 7468 6F72 2773 2070 726F" /* ach author's pro */ - $"7465 6374 696F 6E20 616E 6420 6F75 7273" /* tection and ours */ - $"2C20 7765 2077 616E 7420 746F 206D 616B" /* , we want to mak */ - $"6520 6365 7274 6169 6E0D 7468 6174 2065" /* e certain.that e */ - $"7665 7279 6F6E 6520 756E 6465 7273 7461" /* veryone understa */ - $"6E64 7320 7468 6174 2074 6865 7265 2069" /* nds that there i */ - $"7320 6E6F 2077 6172 7261 6E74 7920 666F" /* s no warranty fo */ - $"7220 7468 6973 2066 7265 650D 736F 6674" /* r this free.soft */ - $"7761 7265 2E20 2049 6620 7468 6520 736F" /* ware. If the so */ - $"6674 7761 7265 2069 7320 6D6F 6469 6669" /* ftware is modifi */ - $"6564 2062 7920 736F 6D65 6F6E 6520 656C" /* ed by someone el */ - $"7365 2061 6E64 2070 6173 7365 6420 6F6E" /* se and passed on */ - $"2C20 7765 0D77 616E 7420 6974 7320 7265" /* , we.want its re */ - $"6369 7069 656E 7473 2074 6F20 6B6E 6F77" /* cipients to know */ - $"2074 6861 7420 7768 6174 2074 6865 7920" /* that what they */ - $"6861 7665 2069 7320 6E6F 7420 7468 6520" /* have is not the */ - $"6F72 6967 696E 616C 2C20 736F 0D74 6861" /* original, so.tha */ - $"7420 616E 7920 7072 6F62 6C65 6D73 2069" /* t any problems i */ - $"6E74 726F 6475 6365 6420 6279 206F 7468" /* ntroduced by oth */ - $"6572 7320 7769 6C6C 206E 6F74 2072 6566" /* ers will not ref */ - $"6C65 6374 206F 6E20 7468 6520 6F72 6967" /* lect on the orig */ - $"696E 616C 0D61 7574 686F 7273 2720 7265" /* inal.authors' re */ - $"7075 7461 7469 6F6E 732E 0D0D 2020 4669" /* putations... Fi */ - $"6E61 6C6C 792C 2061 6E79 2066 7265 6520" /* nally, any free */ - $"7072 6F67 7261 6D20 6973 2074 6872 6561" /* program is threa */ - $"7465 6E65 6420 636F 6E73 7461 6E74 6C79" /* tened constantly */ - $"2062 7920 736F 6674 7761 7265 0D70 6174" /* by software.pat */ - $"656E 7473 2E20 2057 6520 7769 7368 2074" /* ents. We wish t */ - $"6F20 6176 6F69 6420 7468 6520 6461 6E67" /* o avoid the dang */ - $"6572 2074 6861 7420 7265 6469 7374 7269" /* er that redistri */ - $"6275 746F 7273 206F 6620 6120 6672 6565" /* butors of a free */ - $"0D70 726F 6772 616D 2077 696C 6C20 696E" /* .program will in */ - $"6469 7669 6475 616C 6C79 206F 6274 6169" /* dividually obtai */ - $"6E20 7061 7465 6E74 206C 6963 656E 7365" /* n patent license */ - $"732C 2069 6E20 6566 6665 6374 206D 616B" /* s, in effect mak */ - $"696E 6720 7468 650D 7072 6F67 7261 6D20" /* ing the.program */ - $"7072 6F70 7269 6574 6172 792E 2020 546F" /* proprietary. To */ - $"2070 7265 7665 6E74 2074 6869 732C 2077" /* prevent this, w */ - $"6520 6861 7665 206D 6164 6520 6974 2063" /* e have made it c */ - $"6C65 6172 2074 6861 7420 616E 790D 7061" /* lear that any.pa */ - $"7465 6E74 206D 7573 7420 6265 206C 6963" /* tent must be lic */ - $"656E 7365 6420 666F 7220 6576 6572 796F" /* ensed for everyo */ - $"6E65 2773 2066 7265 6520 7573 6520 6F72" /* ne's free use or */ - $"206E 6F74 206C 6963 656E 7365 6420 6174" /* not licensed at */ - $"2061 6C6C 2E0D 0D20 2054 6865 2070 7265" /* all... The pre */ - $"6369 7365 2074 6572 6D73 2061 6E64 2063" /* cise terms and c */ - $"6F6E 6469 7469 6F6E 7320 666F 7220 636F" /* onditions for co */ - $"7079 696E 672C 2064 6973 7472 6962 7574" /* pying, distribut */ - $"696F 6E20 616E 640D 6D6F 6469 6669 6361" /* ion and.modifica */ - $"7469 6F6E 2066 6F6C 6C6F 772E 0D0C 0D09" /* tion follow....Æ */ - $"0920 2020 2047 4E55 2047 454E 4552 414C" /* Æ GNU GENERAL */ - $"2050 5542 4C49 4320 4C49 4345 4E53 450D" /* PUBLIC LICENSE. */ - $"2020 2054 4552 4D53 2041 4E44 2043 4F4E" /* TERMS AND CON */ - $"4449 5449 4F4E 5320 464F 5220 434F 5059" /* DITIONS FOR COPY */ - $"494E 472C 2044 4953 5452 4942 5554 494F" /* ING, DISTRIBUTIO */ - $"4E20 414E 4420 4D4F 4449 4649 4341 5449" /* N AND MODIFICATI */ - $"4F4E 0D0D 2020 302E 2054 6869 7320 4C69" /* ON.. 0. This Li */ - $"6365 6E73 6520 6170 706C 6965 7320 746F" /* cense applies to */ - $"2061 6E79 2070 726F 6772 616D 206F 7220" /* any program or */ - $"6F74 6865 7220 776F 726B 2077 6869 6368" /* other work which */ - $"2063 6F6E 7461 696E 730D 6120 6E6F 7469" /* contains.a noti */ - $"6365 2070 6C61 6365 6420 6279 2074 6865" /* ce placed by the */ - $"2063 6F70 7972 6967 6874 2068 6F6C 6465" /* copyright holde */ - $"7220 7361 7969 6E67 2069 7420 6D61 7920" /* r saying it may */ - $"6265 2064 6973 7472 6962 7574 6564 0D75" /* be distributed.u */ - $"6E64 6572 2074 6865 2074 6572 6D73 206F" /* nder the terms o */ - $"6620 7468 6973 2047 656E 6572 616C 2050" /* f this General P */ - $"7562 6C69 6320 4C69 6365 6E73 652E 2020" /* ublic License. */ - $"5468 6520 2250 726F 6772 616D 222C 2062" /* The "Program", b */ - $"656C 6F77 2C0D 7265 6665 7273 2074 6F20" /* elow,.refers to */ - $"616E 7920 7375 6368 2070 726F 6772 616D" /* any such program */ - $"206F 7220 776F 726B 2C20 616E 6420 6120" /* or work, and a */ - $"2277 6F72 6B20 6261 7365 6420 6F6E 2074" /* "work based on t */ - $"6865 2050 726F 6772 616D 220D 6D65 616E" /* he Program".mean */ - $"7320 6569 7468 6572 2074 6865 2050 726F" /* s either the Pro */ - $"6772 616D 206F 7220 616E 7920 6465 7269" /* gram or any deri */ - $"7661 7469 7665 2077 6F72 6B20 756E 6465" /* vative work unde */ - $"7220 636F 7079 7269 6768 7420 6C61 773A" /* r copyright law: */ - $"0D74 6861 7420 6973 2074 6F20 7361 792C" /* .that is to say, */ - $"2061 2077 6F72 6B20 636F 6E74 6169 6E69" /* a work containi */ - $"6E67 2074 6865 2050 726F 6772 616D 206F" /* ng the Program o */ - $"7220 6120 706F 7274 696F 6E20 6F66 2069" /* r a portion of i */ - $"742C 0D65 6974 6865 7220 7665 7262 6174" /* t,.either verbat */ - $"696D 206F 7220 7769 7468 206D 6F64 6966" /* im or with modif */ - $"6963 6174 696F 6E73 2061 6E64 2F6F 7220" /* ications and/or */ - $"7472 616E 736C 6174 6564 2069 6E74 6F20" /* translated into */ - $"616E 6F74 6865 720D 6C61 6E67 7561 6765" /* another.language */ - $"2E20 2028 4865 7265 696E 6166 7465 722C" /* . (Hereinafter, */ - $"2074 7261 6E73 6C61 7469 6F6E 2069 7320" /* translation is */ - $"696E 636C 7564 6564 2077 6974 686F 7574" /* included without */ - $"206C 696D 6974 6174 696F 6E20 696E 0D74" /* limitation in.t */ - $"6865 2074 6572 6D20 226D 6F64 6966 6963" /* he term "modific */ - $"6174 696F 6E22 2E29 2020 4561 6368 206C" /* ation".) Each l */ - $"6963 656E 7365 6520 6973 2061 6464 7265" /* icensee is addre */ - $"7373 6564 2061 7320 2279 6F75 222E 0D0D" /* ssed as "you"... */ - $"4163 7469 7669 7469 6573 206F 7468 6572" /* Activities other */ - $"2074 6861 6E20 636F 7079 696E 672C 2064" /* than copying, d */ - $"6973 7472 6962 7574 696F 6E20 616E 6420" /* istribution and */ - $"6D6F 6469 6669 6361 7469 6F6E 2061 7265" /* modification are */ - $"206E 6F74 0D63 6F76 6572 6564 2062 7920" /* not.covered by */ - $"7468 6973 204C 6963 656E 7365 3B20 7468" /* this License; th */ - $"6579 2061 7265 206F 7574 7369 6465 2069" /* ey are outside i */ - $"7473 2073 636F 7065 2E20 2054 6865 2061" /* ts scope. The a */ - $"6374 206F 660D 7275 6E6E 696E 6720 7468" /* ct of.running th */ - $"6520 5072 6F67 7261 6D20 6973 206E 6F74" /* e Program is not */ - $"2072 6573 7472 6963 7465 642C 2061 6E64" /* restricted, and */ - $"2074 6865 206F 7574 7075 7420 6672 6F6D" /* the output from */ - $"2074 6865 2050 726F 6772 616D 0D69 7320" /* the Program.is */ - $"636F 7665 7265 6420 6F6E 6C79 2069 6620" /* covered only if */ - $"6974 7320 636F 6E74 656E 7473 2063 6F6E" /* its contents con */ - $"7374 6974 7574 6520 6120 776F 726B 2062" /* stitute a work b */ - $"6173 6564 206F 6E20 7468 650D 5072 6F67" /* ased on the.Prog */ - $"7261 6D20 2869 6E64 6570 656E 6465 6E74" /* ram (independent */ - $"206F 6620 6861 7669 6E67 2062 6565 6E20" /* of having been */ - $"6D61 6465 2062 7920 7275 6E6E 696E 6720" /* made by running */ - $"7468 6520 5072 6F67 7261 6D29 2E0D 5768" /* the Program)..Wh */ - $"6574 6865 7220 7468 6174 2069 7320 7472" /* ether that is tr */ - $"7565 2064 6570 656E 6473 206F 6E20 7768" /* ue depends on wh */ - $"6174 2074 6865 2050 726F 6772 616D 2064" /* at the Program d */ - $"6F65 732E 0D0D 2020 312E 2059 6F75 206D" /* oes... 1. You m */ - $"6179 2063 6F70 7920 616E 6420 6469 7374" /* ay copy and dist */ - $"7269 6275 7465 2076 6572 6261 7469 6D20" /* ribute verbatim */ - $"636F 7069 6573 206F 6620 7468 6520 5072" /* copies of the Pr */ - $"6F67 7261 6D27 730D 736F 7572 6365 2063" /* ogram's.source c */ - $"6F64 6520 6173 2079 6F75 2072 6563 6569" /* ode as you recei */ - $"7665 2069 742C 2069 6E20 616E 7920 6D65" /* ve it, in any me */ - $"6469 756D 2C20 7072 6F76 6964 6564 2074" /* dium, provided t */ - $"6861 7420 796F 750D 636F 6E73 7069 6375" /* hat you.conspicu */ - $"6F75 736C 7920 616E 6420 6170 7072 6F70" /* ously and approp */ - $"7269 6174 656C 7920 7075 626C 6973 6820" /* riately publish */ - $"6F6E 2065 6163 6820 636F 7079 2061 6E20" /* on each copy an */ - $"6170 7072 6F70 7269 6174 650D 636F 7079" /* appropriate.copy */ - $"7269 6768 7420 6E6F 7469 6365 2061 6E64" /* right notice and */ - $"2064 6973 636C 6169 6D65 7220 6F66 2077" /* disclaimer of w */ - $"6172 7261 6E74 793B 206B 6565 7020 696E" /* arranty; keep in */ - $"7461 6374 2061 6C6C 2074 6865 0D6E 6F74" /* tact all the.not */ - $"6963 6573 2074 6861 7420 7265 6665 7220" /* ices that refer */ - $"746F 2074 6869 7320 4C69 6365 6E73 6520" /* to this License */ - $"616E 6420 746F 2074 6865 2061 6273 656E" /* and to the absen */ - $"6365 206F 6620 616E 7920 7761 7272 616E" /* ce of any warran */ - $"7479 3B0D 616E 6420 6769 7665 2061 6E79" /* ty;.and give any */ - $"206F 7468 6572 2072 6563 6970 6965 6E74" /* other recipient */ - $"7320 6F66 2074 6865 2050 726F 6772 616D" /* s of the Program */ - $"2061 2063 6F70 7920 6F66 2074 6869 7320" /* a copy of this */ - $"4C69 6365 6E73 650D 616C 6F6E 6720 7769" /* License.along wi */ - $"7468 2074 6865 2050 726F 6772 616D 2E0D" /* th the Program.. */ - $"0D59 6F75 206D 6179 2063 6861 7267 6520" /* .You may charge */ - $"6120 6665 6520 666F 7220 7468 6520 7068" /* a fee for the ph */ - $"7973 6963 616C 2061 6374 206F 6620 7472" /* ysical act of tr */ - $"616E 7366 6572 7269 6E67 2061 2063 6F70" /* ansferring a cop */ - $"792C 2061 6E64 0D79 6F75 206D 6179 2061" /* y, and.you may a */ - $"7420 796F 7572 206F 7074 696F 6E20 6F66" /* t your option of */ - $"6665 7220 7761 7272 616E 7479 2070 726F" /* fer warranty pro */ - $"7465 6374 696F 6E20 696E 2065 7863 6861" /* tection in excha */ - $"6E67 6520 666F 7220 6120 6665 652E 0D0D" /* nge for a fee... */ - $"2020 322E 2059 6F75 206D 6179 206D 6F64" /* 2. You may mod */ - $"6966 7920 796F 7572 2063 6F70 7920 6F72" /* ify your copy or */ - $"2063 6F70 6965 7320 6F66 2074 6865 2050" /* copies of the P */ - $"726F 6772 616D 206F 7220 616E 7920 706F" /* rogram or any po */ - $"7274 696F 6E0D 6F66 2069 742C 2074 6875" /* rtion.of it, thu */ - $"7320 666F 726D 696E 6720 6120 776F 726B" /* s forming a work */ - $"2062 6173 6564 206F 6E20 7468 6520 5072" /* based on the Pr */ - $"6F67 7261 6D2C 2061 6E64 2063 6F70 7920" /* ogram, and copy */ - $"616E 640D 6469 7374 7269 6275 7465 2073" /* and.distribute s */ - $"7563 6820 6D6F 6469 6669 6361 7469 6F6E" /* uch modification */ - $"7320 6F72 2077 6F72 6B20 756E 6465 7220" /* s or work under */ - $"7468 6520 7465 726D 7320 6F66 2053 6563" /* the terms of Sec */ - $"7469 6F6E 2031 0D61 626F 7665 2C20 7072" /* tion 1.above, pr */ - $"6F76 6964 6564 2074 6861 7420 796F 7520" /* ovided that you */ - $"616C 736F 206D 6565 7420 616C 6C20 6F66" /* also meet all of */ - $"2074 6865 7365 2063 6F6E 6469 7469 6F6E" /* these condition */ - $"733A 0D0D 2020 2020 6129 2059 6F75 206D" /* s:.. a) You m */ - $"7573 7420 6361 7573 6520 7468 6520 6D6F" /* ust cause the mo */ - $"6469 6669 6564 2066 696C 6573 2074 6F20" /* dified files to */ - $"6361 7272 7920 7072 6F6D 696E 656E 7420" /* carry prominent */ - $"6E6F 7469 6365 730D 2020 2020 7374 6174" /* notices. stat */ - $"696E 6720 7468 6174 2079 6F75 2063 6861" /* ing that you cha */ - $"6E67 6564 2074 6865 2066 696C 6573 2061" /* nged the files a */ - $"6E64 2074 6865 2064 6174 6520 6F66 2061" /* nd the date of a */ - $"6E79 2063 6861 6E67 652E 0D0D 2020 2020" /* ny change... */ - $"6229 2059 6F75 206D 7573 7420 6361 7573" /* b) You must caus */ - $"6520 616E 7920 776F 726B 2074 6861 7420" /* e any work that */ - $"796F 7520 6469 7374 7269 6275 7465 206F" /* you distribute o */ - $"7220 7075 626C 6973 682C 2074 6861 7420" /* r publish, that */ - $"696E 0D20 2020 2077 686F 6C65 206F 7220" /* in. whole or */ - $"696E 2070 6172 7420 636F 6E74 6169 6E73" /* in part contains */ - $"206F 7220 6973 2064 6572 6976 6564 2066" /* or is derived f */ - $"726F 6D20 7468 6520 5072 6F67 7261 6D20" /* rom the Program */ - $"6F72 2061 6E79 0D20 2020 2070 6172 7420" /* or any. part */ - $"7468 6572 656F 662C 2074 6F20 6265 206C" /* thereof, to be l */ - $"6963 656E 7365 6420 6173 2061 2077 686F" /* icensed as a who */ - $"6C65 2061 7420 6E6F 2063 6861 7267 6520" /* le at no charge */ - $"746F 2061 6C6C 2074 6869 7264 0D20 2020" /* to all third. */ - $"2070 6172 7469 6573 2075 6E64 6572 2074" /* parties under t */ - $"6865 2074 6572 6D73 206F 6620 7468 6973" /* he terms of this */ - $"204C 6963 656E 7365 2E0D 0D20 2020 2063" /* License... c */ - $"2920 4966 2074 6865 206D 6F64 6966 6965" /* ) If the modifie */ - $"6420 7072 6F67 7261 6D20 6E6F 726D 616C" /* d program normal */ - $"6C79 2072 6561 6473 2063 6F6D 6D61 6E64" /* ly reads command */ - $"7320 696E 7465 7261 6374 6976 656C 790D" /* s interactively. */ - $"2020 2020 7768 656E 2072 756E 2C20 796F" /* when run, yo */ - $"7520 6D75 7374 2063 6175 7365 2069 742C" /* u must cause it, */ - $"2077 6865 6E20 7374 6172 7465 6420 7275" /* when started ru */ - $"6E6E 696E 6720 666F 7220 7375 6368 0D20" /* nning for such. */ - $"2020 2069 6E74 6572 6163 7469 7665 2075" /* interactive u */ - $"7365 2069 6E20 7468 6520 6D6F 7374 206F" /* se in the most o */ - $"7264 696E 6172 7920 7761 792C 2074 6F20" /* rdinary way, to */ - $"7072 696E 7420 6F72 2064 6973 706C 6179" /* print or display */ - $"2061 6E0D 2020 2020 616E 6E6F 756E 6365" /* an. announce */ - $"6D65 6E74 2069 6E63 6C75 6469 6E67 2061" /* ment including a */ - $"6E20 6170 7072 6F70 7269 6174 6520 636F" /* n appropriate co */ - $"7079 7269 6768 7420 6E6F 7469 6365 2061" /* pyright notice a */ - $"6E64 2061 0D20 2020 206E 6F74 6963 6520" /* nd a. notice */ - $"7468 6174 2074 6865 7265 2069 7320 6E6F" /* that there is no */ - $"2077 6172 7261 6E74 7920 286F 7220 656C" /* warranty (or el */ - $"7365 2C20 7361 7969 6E67 2074 6861 7420" /* se, saying that */ - $"796F 7520 7072 6F76 6964 650D 2020 2020" /* you provide. */ - $"6120 7761 7272 616E 7479 2920 616E 6420" /* a warranty) and */ - $"7468 6174 2075 7365 7273 206D 6179 2072" /* that users may r */ - $"6564 6973 7472 6962 7574 6520 7468 6520" /* edistribute the */ - $"7072 6F67 7261 6D20 756E 6465 720D 2020" /* program under. */ - $"2020 7468 6573 6520 636F 6E64 6974 696F" /* these conditio */ - $"6E73 2C20 616E 6420 7465 6C6C 696E 6720" /* ns, and telling */ - $"7468 6520 7573 6572 2068 6F77 2074 6F20" /* the user how to */ - $"7669 6577 2061 2063 6F70 7920 6F66 2074" /* view a copy of t */ - $"6869 730D 2020 2020 4C69 6365 6E73 652E" /* his. License. */ - $"2020 2845 7863 6570 7469 6F6E 3A20 6966" /* (Exception: if */ - $"2074 6865 2050 726F 6772 616D 2069 7473" /* the Program its */ - $"656C 6620 6973 2069 6E74 6572 6163 7469" /* elf is interacti */ - $"7665 2062 7574 0D20 2020 2064 6F65 7320" /* ve but. does */ - $"6E6F 7420 6E6F 726D 616C 6C79 2070 7269" /* not normally pri */ - $"6E74 2073 7563 6820 616E 2061 6E6E 6F75" /* nt such an annou */ - $"6E63 656D 656E 742C 2079 6F75 7220 776F" /* ncement, your wo */ - $"726B 2062 6173 6564 206F 6E0D 2020 2020" /* rk based on. */ - $"7468 6520 5072 6F67 7261 6D20 6973 206E" /* the Program is n */ - $"6F74 2072 6571 7569 7265 6420 746F 2070" /* ot required to p */ - $"7269 6E74 2061 6E20 616E 6E6F 756E 6365" /* rint an announce */ - $"6D65 6E74 2E29 0D0C 0D54 6865 7365 2072" /* ment.)...These r */ - $"6571 7569 7265 6D65 6E74 7320 6170 706C" /* equirements appl */ - $"7920 746F 2074 6865 206D 6F64 6966 6965" /* y to the modifie */ - $"6420 776F 726B 2061 7320 6120 7768 6F6C" /* d work as a whol */ - $"652E 2020 4966 0D69 6465 6E74 6966 6961" /* e. If.identifia */ - $"626C 6520 7365 6374 696F 6E73 206F 6620" /* ble sections of */ - $"7468 6174 2077 6F72 6B20 6172 6520 6E6F" /* that work are no */ - $"7420 6465 7269 7665 6420 6672 6F6D 2074" /* t derived from t */ - $"6865 2050 726F 6772 616D 2C0D 616E 6420" /* he Program,.and */ - $"6361 6E20 6265 2072 6561 736F 6E61 626C" /* can be reasonabl */ - $"7920 636F 6E73 6964 6572 6564 2069 6E64" /* y considered ind */ - $"6570 656E 6465 6E74 2061 6E64 2073 6570" /* ependent and sep */ - $"6172 6174 6520 776F 726B 7320 696E 0D74" /* arate works in.t */ - $"6865 6D73 656C 7665 732C 2074 6865 6E20" /* hemselves, then */ - $"7468 6973 204C 6963 656E 7365 2C20 616E" /* this License, an */ - $"6420 6974 7320 7465 726D 732C 2064 6F20" /* d its terms, do */ - $"6E6F 7420 6170 706C 7920 746F 2074 686F" /* not apply to tho */ - $"7365 0D73 6563 7469 6F6E 7320 7768 656E" /* se.sections when */ - $"2079 6F75 2064 6973 7472 6962 7574 6520" /* you distribute */ - $"7468 656D 2061 7320 7365 7061 7261 7465" /* them as separate */ - $"2077 6F72 6B73 2E20 2042 7574 2077 6865" /* works. But whe */ - $"6E20 796F 750D 6469 7374 7269 6275 7465" /* n you.distribute */ - $"2074 6865 2073 616D 6520 7365 6374 696F" /* the same sectio */ - $"6E73 2061 7320 7061 7274 206F 6620 6120" /* ns as part of a */ - $"7768 6F6C 6520 7768 6963 6820 6973 2061" /* whole which is a */ - $"2077 6F72 6B20 6261 7365 640D 6F6E 2074" /* work based.on t */ - $"6865 2050 726F 6772 616D 2C20 7468 6520" /* he Program, the */ - $"6469 7374 7269 6275 7469 6F6E 206F 6620" /* distribution of */ - $"7468 6520 7768 6F6C 6520 6D75 7374 2062" /* the whole must b */ - $"6520 6F6E 2074 6865 2074 6572 6D73 206F" /* e on the terms o */ - $"660D 7468 6973 204C 6963 656E 7365 2C20" /* f.this License, */ - $"7768 6F73 6520 7065 726D 6973 7369 6F6E" /* whose permission */ - $"7320 666F 7220 6F74 6865 7220 6C69 6365" /* s for other lice */ - $"6E73 6565 7320 6578 7465 6E64 2074 6F20" /* nsees extend to */ - $"7468 650D 656E 7469 7265 2077 686F 6C65" /* the.entire whole */ - $"2C20 616E 6420 7468 7573 2074 6F20 6561" /* , and thus to ea */ - $"6368 2061 6E64 2065 7665 7279 2070 6172" /* ch and every par */ - $"7420 7265 6761 7264 6C65 7373 206F 6620" /* t regardless of */ - $"7768 6F20 7772 6F74 6520 6974 2E0D 0D54" /* who wrote it...T */ - $"6875 732C 2069 7420 6973 206E 6F74 2074" /* hus, it is not t */ - $"6865 2069 6E74 656E 7420 6F66 2074 6869" /* he intent of thi */ - $"7320 7365 6374 696F 6E20 746F 2063 6C61" /* s section to cla */ - $"696D 2072 6967 6874 7320 6F72 2063 6F6E" /* im rights or con */ - $"7465 7374 0D79 6F75 7220 7269 6768 7473" /* test.your rights */ - $"2074 6F20 776F 726B 2077 7269 7474 656E" /* to work written */ - $"2065 6E74 6972 656C 7920 6279 2079 6F75" /* entirely by you */ - $"3B20 7261 7468 6572 2C20 7468 6520 696E" /* ; rather, the in */ - $"7465 6E74 2069 7320 746F 0D65 7865 7263" /* tent is to.exerc */ - $"6973 6520 7468 6520 7269 6768 7420 746F" /* ise the right to */ - $"2063 6F6E 7472 6F6C 2074 6865 2064 6973" /* control the dis */ - $"7472 6962 7574 696F 6E20 6F66 2064 6572" /* tribution of der */ - $"6976 6174 6976 6520 6F72 0D63 6F6C 6C65" /* ivative or.colle */ - $"6374 6976 6520 776F 726B 7320 6261 7365" /* ctive works base */ - $"6420 6F6E 2074 6865 2050 726F 6772 616D" /* d on the Program */ - $"2E0D 0D49 6E20 6164 6469 7469 6F6E 2C20" /* ...In addition, */ - $"6D65 7265 2061 6767 7265 6761 7469 6F6E" /* mere aggregation */ - $"206F 6620 616E 6F74 6865 7220 776F 726B" /* of another work */ - $"206E 6F74 2062 6173 6564 206F 6E20 7468" /* not based on th */ - $"6520 5072 6F67 7261 6D0D 7769 7468 2074" /* e Program.with t */ - $"6865 2050 726F 6772 616D 2028 6F72 2077" /* he Program (or w */ - $"6974 6820 6120 776F 726B 2062 6173 6564" /* ith a work based */ - $"206F 6E20 7468 6520 5072 6F67 7261 6D29" /* on the Program) */ - $"206F 6E20 6120 766F 6C75 6D65 206F 660D" /* on a volume of. */ - $"6120 7374 6F72 6167 6520 6F72 2064 6973" /* a storage or dis */ - $"7472 6962 7574 696F 6E20 6D65 6469 756D" /* tribution medium */ - $"2064 6F65 7320 6E6F 7420 6272 696E 6720" /* does not bring */ - $"7468 6520 6F74 6865 7220 776F 726B 2075" /* the other work u */ - $"6E64 6572 0D74 6865 2073 636F 7065 206F" /* nder.the scope o */ - $"6620 7468 6973 204C 6963 656E 7365 2E0D" /* f this License.. */ - $"0D20 2033 2E20 596F 7520 6D61 7920 636F" /* . 3. You may co */ - $"7079 2061 6E64 2064 6973 7472 6962 7574" /* py and distribut */ - $"6520 7468 6520 5072 6F67 7261 6D20 286F" /* e the Program (o */ - $"7220 6120 776F 726B 2062 6173 6564 206F" /* r a work based o */ - $"6E20 6974 2C0D 756E 6465 7220 5365 6374" /* n it,.under Sect */ - $"696F 6E20 3229 2069 6E20 6F62 6A65 6374" /* ion 2) in object */ - $"2063 6F64 6520 6F72 2065 7865 6375 7461" /* code or executa */ - $"626C 6520 666F 726D 2075 6E64 6572 2074" /* ble form under t */ - $"6865 2074 6572 6D73 206F 660D 5365 6374" /* he terms of.Sect */ - $"696F 6E73 2031 2061 6E64 2032 2061 626F" /* ions 1 and 2 abo */ - $"7665 2070 726F 7669 6465 6420 7468 6174" /* ve provided that */ - $"2079 6F75 2061 6C73 6F20 646F 206F 6E65" /* you also do one */ - $"206F 6620 7468 6520 666F 6C6C 6F77 696E" /* of the followin */ - $"673A 0D0D 2020 2020 6129 2041 6363 6F6D" /* g:.. a) Accom */ - $"7061 6E79 2069 7420 7769 7468 2074 6865" /* pany it with the */ - $"2063 6F6D 706C 6574 6520 636F 7272 6573" /* complete corres */ - $"706F 6E64 696E 6720 6D61 6368 696E 652D" /* ponding machine- */ - $"7265 6164 6162 6C65 0D20 2020 2073 6F75" /* readable. sou */ - $"7263 6520 636F 6465 2C20 7768 6963 6820" /* rce code, which */ - $"6D75 7374 2062 6520 6469 7374 7269 6275" /* must be distribu */ - $"7465 6420 756E 6465 7220 7468 6520 7465" /* ted under the te */ - $"726D 7320 6F66 2053 6563 7469 6F6E 730D" /* rms of Sections. */ - $"2020 2020 3120 616E 6420 3220 6162 6F76" /* 1 and 2 abov */ - $"6520 6F6E 2061 206D 6564 6975 6D20 6375" /* e on a medium cu */ - $"7374 6F6D 6172 696C 7920 7573 6564 2066" /* stomarily used f */ - $"6F72 2073 6F66 7477 6172 6520 696E 7465" /* or software inte */ - $"7263 6861 6E67 653B 206F 722C 0D0D 2020" /* rchange; or,.. */ - $"2020 6229 2041 6363 6F6D 7061 6E79 2069" /* b) Accompany i */ - $"7420 7769 7468 2061 2077 7269 7474 656E" /* t with a written */ - $"206F 6666 6572 2C20 7661 6C69 6420 666F" /* offer, valid fo */ - $"7220 6174 206C 6561 7374 2074 6872 6565" /* r at least three */ - $"0D20 2020 2079 6561 7273 2C20 746F 2067" /* . years, to g */ - $"6976 6520 616E 7920 7468 6972 6420 7061" /* ive any third pa */ - $"7274 792C 2066 6F72 2061 2063 6861 7267" /* rty, for a charg */ - $"6520 6E6F 206D 6F72 6520 7468 616E 2079" /* e no more than y */ - $"6F75 720D 2020 2020 636F 7374 206F 6620" /* our. cost of */ - $"7068 7973 6963 616C 6C79 2070 6572 666F" /* physically perfo */ - $"726D 696E 6720 736F 7572 6365 2064 6973" /* rming source dis */ - $"7472 6962 7574 696F 6E2C 2061 2063 6F6D" /* tribution, a com */ - $"706C 6574 650D 2020 2020 6D61 6368 696E" /* plete. machin */ - $"652D 7265 6164 6162 6C65 2063 6F70 7920" /* e-readable copy */ - $"6F66 2074 6865 2063 6F72 7265 7370 6F6E" /* of the correspon */ - $"6469 6E67 2073 6F75 7263 6520 636F 6465" /* ding source code */ - $"2C20 746F 2062 650D 2020 2020 6469 7374" /* , to be. dist */ - $"7269 6275 7465 6420 756E 6465 7220 7468" /* ributed under th */ - $"6520 7465 726D 7320 6F66 2053 6563 7469" /* e terms of Secti */ - $"6F6E 7320 3120 616E 6420 3220 6162 6F76" /* ons 1 and 2 abov */ - $"6520 6F6E 2061 206D 6564 6975 6D0D 2020" /* e on a medium. */ - $"2020 6375 7374 6F6D 6172 696C 7920 7573" /* customarily us */ - $"6564 2066 6F72 2073 6F66 7477 6172 6520" /* ed for software */ - $"696E 7465 7263 6861 6E67 653B 206F 722C" /* interchange; or, */ - $"0D0D 2020 2020 6329 2041 6363 6F6D 7061" /* .. c) Accompa */ - $"6E79 2069 7420 7769 7468 2074 6865 2069" /* ny it with the i */ - $"6E66 6F72 6D61 7469 6F6E 2079 6F75 2072" /* nformation you r */ - $"6563 6569 7665 6420 6173 2074 6F20 7468" /* eceived as to th */ - $"6520 6F66 6665 720D 2020 2020 746F 2064" /* e offer. to d */ - $"6973 7472 6962 7574 6520 636F 7272 6573" /* istribute corres */ - $"706F 6E64 696E 6720 736F 7572 6365 2063" /* ponding source c */ - $"6F64 652E 2020 2854 6869 7320 616C 7465" /* ode. (This alte */ - $"726E 6174 6976 6520 6973 0D20 2020 2061" /* rnative is. a */ - $"6C6C 6F77 6564 206F 6E6C 7920 666F 7220" /* llowed only for */ - $"6E6F 6E63 6F6D 6D65 7263 6961 6C20 6469" /* noncommercial di */ - $"7374 7269 6275 7469 6F6E 2061 6E64 206F" /* stribution and o */ - $"6E6C 7920 6966 2079 6F75 0D20 2020 2072" /* nly if you. r */ - $"6563 6569 7665 6420 7468 6520 7072 6F67" /* eceived the prog */ - $"7261 6D20 696E 206F 626A 6563 7420 636F" /* ram in object co */ - $"6465 206F 7220 6578 6563 7574 6162 6C65" /* de or executable */ - $"2066 6F72 6D20 7769 7468 2073 7563 680D" /* form with such. */ - $"2020 2020 616E 206F 6666 6572 2C20 696E" /* an offer, in */ - $"2061 6363 6F72 6420 7769 7468 2053 7562" /* accord with Sub */ - $"7365 6374 696F 6E20 6220 6162 6F76 652E" /* section b above. */ - $"290D 0D54 6865 2073 6F75 7263 6520 636F" /* )..The source co */ - $"6465 2066 6F72 2061 2077 6F72 6B20 6D65" /* de for a work me */ - $"616E 7320 7468 6520 7072 6566 6572 7265" /* ans the preferre */ - $"6420 666F 726D 206F 6620 7468 6520 776F" /* d form of the wo */ - $"726B 2066 6F72 0D6D 616B 696E 6720 6D6F" /* rk for.making mo */ - $"6469 6669 6361 7469 6F6E 7320 746F 2069" /* difications to i */ - $"742E 2020 466F 7220 616E 2065 7865 6375" /* t. For an execu */ - $"7461 626C 6520 776F 726B 2C20 636F 6D70" /* table work, comp */ - $"6C65 7465 2073 6F75 7263 650D 636F 6465" /* lete source.code */ - $"206D 6561 6E73 2061 6C6C 2074 6865 2073" /* means all the s */ - $"6F75 7263 6520 636F 6465 2066 6F72 2061" /* ource code for a */ - $"6C6C 206D 6F64 756C 6573 2069 7420 636F" /* ll modules it co */ - $"6E74 6169 6E73 2C20 706C 7573 2061 6E79" /* ntains, plus any */ - $"0D61 7373 6F63 6961 7465 6420 696E 7465" /* .associated inte */ - $"7266 6163 6520 6465 6669 6E69 7469 6F6E" /* rface definition */ - $"2066 696C 6573 2C20 706C 7573 2074 6865" /* files, plus the */ - $"2073 6372 6970 7473 2075 7365 6420 746F" /* scripts used to */ - $"0D63 6F6E 7472 6F6C 2063 6F6D 7069 6C61" /* .control compila */ - $"7469 6F6E 2061 6E64 2069 6E73 7461 6C6C" /* tion and install */ - $"6174 696F 6E20 6F66 2074 6865 2065 7865" /* ation of the exe */ - $"6375 7461 626C 652E 2020 486F 7765 7665" /* cutable. Howeve */ - $"722C 2061 7320 610D 7370 6563 6961 6C20" /* r, as a.special */ - $"6578 6365 7074 696F 6E2C 2074 6865 2073" /* exception, the s */ - $"6F75 7263 6520 636F 6465 2064 6973 7472" /* ource code distr */ - $"6962 7574 6564 206E 6565 6420 6E6F 7420" /* ibuted need not */ - $"696E 636C 7564 650D 616E 7974 6869 6E67" /* include.anything */ - $"2074 6861 7420 6973 206E 6F72 6D61 6C6C" /* that is normall */ - $"7920 6469 7374 7269 6275 7465 6420 2869" /* y distributed (i */ - $"6E20 6569 7468 6572 2073 6F75 7263 6520" /* n either source */ - $"6F72 2062 696E 6172 790D 666F 726D 2920" /* or binary.form) */ - $"7769 7468 2074 6865 206D 616A 6F72 2063" /* with the major c */ - $"6F6D 706F 6E65 6E74 7320 2863 6F6D 7069" /* omponents (compi */ - $"6C65 722C 206B 6572 6E65 6C2C 2061 6E64" /* ler, kernel, and */ - $"2073 6F20 6F6E 2920 6F66 2074 6865 0D6F" /* so on) of the.o */ - $"7065 7261 7469 6E67 2073 7973 7465 6D20" /* perating system */ - $"6F6E 2077 6869 6368 2074 6865 2065 7865" /* on which the exe */ - $"6375 7461 626C 6520 7275 6E73 2C20 756E" /* cutable runs, un */ - $"6C65 7373 2074 6861 7420 636F 6D70 6F6E" /* less that compon */ - $"656E 740D 6974 7365 6C66 2061 6363 6F6D" /* ent.itself accom */ - $"7061 6E69 6573 2074 6865 2065 7865 6375" /* panies the execu */ - $"7461 626C 652E 0D0D 4966 2064 6973 7472" /* table...If distr */ - $"6962 7574 696F 6E20 6F66 2065 7865 6375" /* ibution of execu */ - $"7461 626C 6520 6F72 206F 626A 6563 7420" /* table or object */ - $"636F 6465 2069 7320 6D61 6465 2062 7920" /* code is made by */ - $"6F66 6665 7269 6E67 0D61 6363 6573 7320" /* offering.access */ - $"746F 2063 6F70 7920 6672 6F6D 2061 2064" /* to copy from a d */ - $"6573 6967 6E61 7465 6420 706C 6163 652C" /* esignated place, */ - $"2074 6865 6E20 6F66 6665 7269 6E67 2065" /* then offering e */ - $"7175 6976 616C 656E 740D 6163 6365 7373" /* quivalent.access */ - $"2074 6F20 636F 7079 2074 6865 2073 6F75" /* to copy the sou */ - $"7263 6520 636F 6465 2066 726F 6D20 7468" /* rce code from th */ - $"6520 7361 6D65 2070 6C61 6365 2063 6F75" /* e same place cou */ - $"6E74 7320 6173 0D64 6973 7472 6962 7574" /* nts as.distribut */ - $"696F 6E20 6F66 2074 6865 2073 6F75 7263" /* ion of the sourc */ - $"6520 636F 6465 2C20 6576 656E 2074 686F" /* e code, even tho */ - $"7567 6820 7468 6972 6420 7061 7274 6965" /* ugh third partie */ - $"7320 6172 6520 6E6F 740D 636F 6D70 656C" /* s are not.compel */ - $"6C65 6420 746F 2063 6F70 7920 7468 6520" /* led to copy the */ - $"736F 7572 6365 2061 6C6F 6E67 2077 6974" /* source along wit */ - $"6820 7468 6520 6F62 6A65 6374 2063 6F64" /* h the object cod */ - $"652E 0D0C 0D20 2034 2E20 596F 7520 6D61" /* e.... 4. You ma */ - $"7920 6E6F 7420 636F 7079 2C20 6D6F 6469" /* y not copy, modi */ - $"6679 2C20 7375 626C 6963 656E 7365 2C20" /* fy, sublicense, */ - $"6F72 2064 6973 7472 6962 7574 6520 7468" /* or distribute th */ - $"6520 5072 6F67 7261 6D0D 6578 6365 7074" /* e Program.except */ - $"2061 7320 6578 7072 6573 736C 7920 7072" /* as expressly pr */ - $"6F76 6964 6564 2075 6E64 6572 2074 6869" /* ovided under thi */ - $"7320 4C69 6365 6E73 652E 2020 416E 7920" /* s License. Any */ - $"6174 7465 6D70 740D 6F74 6865 7277 6973" /* attempt.otherwis */ - $"6520 746F 2063 6F70 792C 206D 6F64 6966" /* e to copy, modif */ - $"792C 2073 7562 6C69 6365 6E73 6520 6F72" /* y, sublicense or */ - $"2064 6973 7472 6962 7574 6520 7468 6520" /* distribute the */ - $"5072 6F67 7261 6D20 6973 0D76 6F69 642C" /* Program is.void, */ - $"2061 6E64 2077 696C 6C20 6175 746F 6D61" /* and will automa */ - $"7469 6361 6C6C 7920 7465 726D 696E 6174" /* tically terminat */ - $"6520 796F 7572 2072 6967 6874 7320 756E" /* e your rights un */ - $"6465 7220 7468 6973 204C 6963 656E 7365" /* der this License */ - $"2E0D 486F 7765 7665 722C 2070 6172 7469" /* ..However, parti */ - $"6573 2077 686F 2068 6176 6520 7265 6365" /* es who have rece */ - $"6976 6564 2063 6F70 6965 732C 206F 7220" /* ived copies, or */ - $"7269 6768 7473 2C20 6672 6F6D 2079 6F75" /* rights, from you */ - $"2075 6E64 6572 0D74 6869 7320 4C69 6365" /* under.this Lice */ - $"6E73 6520 7769 6C6C 206E 6F74 2068 6176" /* nse will not hav */ - $"6520 7468 6569 7220 6C69 6365 6E73 6573" /* e their licenses */ - $"2074 6572 6D69 6E61 7465 6420 736F 206C" /* terminated so l */ - $"6F6E 6720 6173 2073 7563 680D 7061 7274" /* ong as such.part */ - $"6965 7320 7265 6D61 696E 2069 6E20 6675" /* ies remain in fu */ - $"6C6C 2063 6F6D 706C 6961 6E63 652E 0D0D" /* ll compliance... */ - $"2020 352E 2059 6F75 2061 7265 206E 6F74" /* 5. You are not */ - $"2072 6571 7569 7265 6420 746F 2061 6363" /* required to acc */ - $"6570 7420 7468 6973 204C 6963 656E 7365" /* ept this License */ - $"2C20 7369 6E63 6520 796F 7520 6861 7665" /* , since you have */ - $"206E 6F74 0D73 6967 6E65 6420 6974 2E20" /* not.signed it. */ - $"2048 6F77 6576 6572 2C20 6E6F 7468 696E" /* However, nothin */ - $"6720 656C 7365 2067 7261 6E74 7320 796F" /* g else grants yo */ - $"7520 7065 726D 6973 7369 6F6E 2074 6F20" /* u permission to */ - $"6D6F 6469 6679 206F 720D 6469 7374 7269" /* modify or.distri */ - $"6275 7465 2074 6865 2050 726F 6772 616D" /* bute the Program */ - $"206F 7220 6974 7320 6465 7269 7661 7469" /* or its derivati */ - $"7665 2077 6F72 6B73 2E20 2054 6865 7365" /* ve works. These */ - $"2061 6374 696F 6E73 2061 7265 0D70 726F" /* actions are.pro */ - $"6869 6269 7465 6420 6279 206C 6177 2069" /* hibited by law i */ - $"6620 796F 7520 646F 206E 6F74 2061 6363" /* f you do not acc */ - $"6570 7420 7468 6973 204C 6963 656E 7365" /* ept this License */ - $"2E20 2054 6865 7265 666F 7265 2C20 6279" /* . Therefore, by */ - $"0D6D 6F64 6966 7969 6E67 206F 7220 6469" /* .modifying or di */ - $"7374 7269 6275 7469 6E67 2074 6865 2050" /* stributing the P */ - $"726F 6772 616D 2028 6F72 2061 6E79 2077" /* rogram (or any w */ - $"6F72 6B20 6261 7365 6420 6F6E 2074 6865" /* ork based on the */ - $"0D50 726F 6772 616D 292C 2079 6F75 2069" /* .Program), you i */ - $"6E64 6963 6174 6520 796F 7572 2061 6363" /* ndicate your acc */ - $"6570 7461 6E63 6520 6F66 2074 6869 7320" /* eptance of this */ - $"4C69 6365 6E73 6520 746F 2064 6F20 736F" /* License to do so */ - $"2C20 616E 640D 616C 6C20 6974 7320 7465" /* , and.all its te */ - $"726D 7320 616E 6420 636F 6E64 6974 696F" /* rms and conditio */ - $"6E73 2066 6F72 2063 6F70 7969 6E67 2C20" /* ns for copying, */ - $"6469 7374 7269 6275 7469 6E67 206F 7220" /* distributing or */ - $"6D6F 6469 6679 696E 670D 7468 6520 5072" /* modifying.the Pr */ - $"6F67 7261 6D20 6F72 2077 6F72 6B73 2062" /* ogram or works b */ - $"6173 6564 206F 6E20 6974 2E0D 0D20 2036" /* ased on it... 6 */ - $"2E20 4561 6368 2074 696D 6520 796F 7520" /* . Each time you */ - $"7265 6469 7374 7269 6275 7465 2074 6865" /* redistribute the */ - $"2050 726F 6772 616D 2028 6F72 2061 6E79" /* Program (or any */ - $"2077 6F72 6B20 6261 7365 6420 6F6E 2074" /* work based on t */ - $"6865 0D50 726F 6772 616D 292C 2074 6865" /* he.Program), the */ - $"2072 6563 6970 6965 6E74 2061 7574 6F6D" /* recipient autom */ - $"6174 6963 616C 6C79 2072 6563 6569 7665" /* atically receive */ - $"7320 6120 6C69 6365 6E73 6520 6672 6F6D" /* s a license from */ - $"2074 6865 0D6F 7269 6769 6E61 6C20 6C69" /* the.original li */ - $"6365 6E73 6F72 2074 6F20 636F 7079 2C20" /* censor to copy, */ - $"6469 7374 7269 6275 7465 206F 7220 6D6F" /* distribute or mo */ - $"6469 6679 2074 6865 2050 726F 6772 616D" /* dify the Program */ - $"2073 7562 6A65 6374 2074 6F0D 7468 6573" /* subject to.thes */ - $"6520 7465 726D 7320 616E 6420 636F 6E64" /* e terms and cond */ - $"6974 696F 6E73 2E20 2059 6F75 206D 6179" /* itions. You may */ - $"206E 6F74 2069 6D70 6F73 6520 616E 7920" /* not impose any */ - $"6675 7274 6865 720D 7265 7374 7269 6374" /* further.restrict */ - $"696F 6E73 206F 6E20 7468 6520 7265 6369" /* ions on the reci */ - $"7069 656E 7473 2720 6578 6572 6369 7365" /* pients' exercise */ - $"206F 6620 7468 6520 7269 6768 7473 2067" /* of the rights g */ - $"7261 6E74 6564 2068 6572 6569 6E2E 0D59" /* ranted herein..Y */ - $"6F75 2061 7265 206E 6F74 2072 6573 706F" /* ou are not respo */ - $"6E73 6962 6C65 2066 6F72 2065 6E66 6F72" /* nsible for enfor */ - $"6369 6E67 2063 6F6D 706C 6961 6E63 6520" /* cing compliance */ - $"6279 2074 6869 7264 2070 6172 7469 6573" /* by third parties */ - $"2074 6F0D 7468 6973 204C 6963 656E 7365" /* to.this License */ - $"2E0D 0D20 2037 2E20 4966 2C20 6173 2061" /* ... 7. If, as a */ - $"2063 6F6E 7365 7175 656E 6365 206F 6620" /* consequence of */ - $"6120 636F 7572 7420 6A75 6467 6D65 6E74" /* a court judgment */ - $"206F 7220 616C 6C65 6761 7469 6F6E 206F" /* or allegation o */ - $"6620 7061 7465 6E74 0D69 6E66 7269 6E67" /* f patent.infring */ - $"656D 656E 7420 6F72 2066 6F72 2061 6E79" /* ement or for any */ - $"206F 7468 6572 2072 6561 736F 6E20 286E" /* other reason (n */ - $"6F74 206C 696D 6974 6564 2074 6F20 7061" /* ot limited to pa */ - $"7465 6E74 2069 7373 7565 7329 2C0D 636F" /* tent issues),.co */ - $"6E64 6974 696F 6E73 2061 7265 2069 6D70" /* nditions are imp */ - $"6F73 6564 206F 6E20 796F 7520 2877 6865" /* osed on you (whe */ - $"7468 6572 2062 7920 636F 7572 7420 6F72" /* ther by court or */ - $"6465 722C 2061 6772 6565 6D65 6E74 206F" /* der, agreement o */ - $"720D 6F74 6865 7277 6973 6529 2074 6861" /* r.otherwise) tha */ - $"7420 636F 6E74 7261 6469 6374 2074 6865" /* t contradict the */ - $"2063 6F6E 6469 7469 6F6E 7320 6F66 2074" /* conditions of t */ - $"6869 7320 4C69 6365 6E73 652C 2074 6865" /* his License, the */ - $"7920 646F 206E 6F74 0D65 7863 7573 6520" /* y do not.excuse */ - $"796F 7520 6672 6F6D 2074 6865 2063 6F6E" /* you from the con */ - $"6469 7469 6F6E 7320 6F66 2074 6869 7320" /* ditions of this */ - $"4C69 6365 6E73 652E 2020 4966 2079 6F75" /* License. If you */ - $"2063 616E 6E6F 740D 6469 7374 7269 6275" /* cannot.distribu */ - $"7465 2073 6F20 6173 2074 6F20 7361 7469" /* te so as to sati */ - $"7366 7920 7369 6D75 6C74 616E 656F 7573" /* sfy simultaneous */ - $"6C79 2079 6F75 7220 6F62 6C69 6761 7469" /* ly your obligati */ - $"6F6E 7320 756E 6465 7220 7468 6973 0D4C" /* ons under this.L */ - $"6963 656E 7365 2061 6E64 2061 6E79 206F" /* icense and any o */ - $"7468 6572 2070 6572 7469 6E65 6E74 206F" /* ther pertinent o */ - $"626C 6967 6174 696F 6E73 2C20 7468 656E" /* bligations, then */ - $"2061 7320 6120 636F 6E73 6571 7565 6E63" /* as a consequenc */ - $"6520 796F 750D 6D61 7920 6E6F 7420 6469" /* e you.may not di */ - $"7374 7269 6275 7465 2074 6865 2050 726F" /* stribute the Pro */ - $"6772 616D 2061 7420 616C 6C2E 2020 466F" /* gram at all. Fo */ - $"7220 6578 616D 706C 652C 2069 6620 6120" /* r example, if a */ - $"7061 7465 6E74 0D6C 6963 656E 7365 2077" /* patent.license w */ - $"6F75 6C64 206E 6F74 2070 6572 6D69 7420" /* ould not permit */ - $"726F 7961 6C74 792D 6672 6565 2072 6564" /* royalty-free red */ - $"6973 7472 6962 7574 696F 6E20 6F66 2074" /* istribution of t */ - $"6865 2050 726F 6772 616D 2062 790D 616C" /* he Program by.al */ - $"6C20 7468 6F73 6520 7768 6F20 7265 6365" /* l those who rece */ - $"6976 6520 636F 7069 6573 2064 6972 6563" /* ive copies direc */ - $"746C 7920 6F72 2069 6E64 6972 6563 746C" /* tly or indirectl */ - $"7920 7468 726F 7567 6820 796F 752C 2074" /* y through you, t */ - $"6865 6E0D 7468 6520 6F6E 6C79 2077 6179" /* hen.the only way */ - $"2079 6F75 2063 6F75 6C64 2073 6174 6973" /* you could satis */ - $"6679 2062 6F74 6820 6974 2061 6E64 2074" /* fy both it and t */ - $"6869 7320 4C69 6365 6E73 6520 776F 756C" /* his License woul */ - $"6420 6265 2074 6F0D 7265 6672 6169 6E20" /* d be to.refrain */ - $"656E 7469 7265 6C79 2066 726F 6D20 6469" /* entirely from di */ - $"7374 7269 6275 7469 6F6E 206F 6620 7468" /* stribution of th */ - $"6520 5072 6F67 7261 6D2E 0D0D 4966 2061" /* e Program...If a */ - $"6E79 2070 6F72 7469 6F6E 206F 6620 7468" /* ny portion of th */ - $"6973 2073 6563 7469 6F6E 2069 7320 6865" /* is section is he */ - $"6C64 2069 6E76 616C 6964 206F 7220 756E" /* ld invalid or un */ - $"656E 666F 7263 6561 626C 6520 756E 6465" /* enforceable unde */ - $"720D 616E 7920 7061 7274 6963 756C 6172" /* r.any particular */ - $"2063 6972 6375 6D73 7461 6E63 652C 2074" /* circumstance, t */ - $"6865 2062 616C 616E 6365 206F 6620 7468" /* he balance of th */ - $"6520 7365 6374 696F 6E20 6973 2069 6E74" /* e section is int */ - $"656E 6465 6420 746F 0D61 7070 6C79 2061" /* ended to.apply a */ - $"6E64 2074 6865 2073 6563 7469 6F6E 2061" /* nd the section a */ - $"7320 6120 7768 6F6C 6520 6973 2069 6E74" /* s a whole is int */ - $"656E 6465 6420 746F 2061 7070 6C79 2069" /* ended to apply i */ - $"6E20 6F74 6865 720D 6369 7263 756D 7374" /* n other.circumst */ - $"616E 6365 732E 0D0D 4974 2069 7320 6E6F" /* ances...It is no */ - $"7420 7468 6520 7075 7270 6F73 6520 6F66" /* t the purpose of */ - $"2074 6869 7320 7365 6374 696F 6E20 746F" /* this section to */ - $"2069 6E64 7563 6520 796F 7520 746F 2069" /* induce you to i */ - $"6E66 7269 6E67 6520 616E 790D 7061 7465" /* nfringe any.pate */ - $"6E74 7320 6F72 206F 7468 6572 2070 726F" /* nts or other pro */ - $"7065 7274 7920 7269 6768 7420 636C 6169" /* perty right clai */ - $"6D73 206F 7220 746F 2063 6F6E 7465 7374" /* ms or to contest */ - $"2076 616C 6964 6974 7920 6F66 2061 6E79" /* validity of any */ - $"0D73 7563 6820 636C 6169 6D73 3B20 7468" /* .such claims; th */ - $"6973 2073 6563 7469 6F6E 2068 6173 2074" /* is section has t */ - $"6865 2073 6F6C 6520 7075 7270 6F73 6520" /* he sole purpose */ - $"6F66 2070 726F 7465 6374 696E 6720 7468" /* of protecting th */ - $"650D 696E 7465 6772 6974 7920 6F66 2074" /* e.integrity of t */ - $"6865 2066 7265 6520 736F 6674 7761 7265" /* he free software */ - $"2064 6973 7472 6962 7574 696F 6E20 7379" /* distribution sy */ - $"7374 656D 2C20 7768 6963 6820 6973 0D69" /* stem, which is.i */ - $"6D70 6C65 6D65 6E74 6564 2062 7920 7075" /* mplemented by pu */ - $"626C 6963 206C 6963 656E 7365 2070 7261" /* blic license pra */ - $"6374 6963 6573 2E20 204D 616E 7920 7065" /* ctices. Many pe */ - $"6F70 6C65 2068 6176 6520 6D61 6465 0D67" /* ople have made.g */ - $"656E 6572 6F75 7320 636F 6E74 7269 6275" /* enerous contribu */ - $"7469 6F6E 7320 746F 2074 6865 2077 6964" /* tions to the wid */ - $"6520 7261 6E67 6520 6F66 2073 6F66 7477" /* e range of softw */ - $"6172 6520 6469 7374 7269 6275 7465 640D" /* are distributed. */ - $"7468 726F 7567 6820 7468 6174 2073 7973" /* through that sys */ - $"7465 6D20 696E 2072 656C 6961 6E63 6520" /* tem in reliance */ - $"6F6E 2063 6F6E 7369 7374 656E 7420 6170" /* on consistent ap */ - $"706C 6963 6174 696F 6E20 6F66 2074 6861" /* plication of tha */ - $"740D 7379 7374 656D 3B20 6974 2069 7320" /* t.system; it is */ - $"7570 2074 6F20 7468 6520 6175 7468 6F72" /* up to the author */ - $"2F64 6F6E 6F72 2074 6F20 6465 6369 6465" /* /donor to decide */ - $"2069 6620 6865 206F 7220 7368 6520 6973" /* if he or she is */ - $"2077 696C 6C69 6E67 0D74 6F20 6469 7374" /* willing.to dist */ - $"7269 6275 7465 2073 6F66 7477 6172 6520" /* ribute software */ - $"7468 726F 7567 6820 616E 7920 6F74 6865" /* through any othe */ - $"7220 7379 7374 656D 2061 6E64 2061 206C" /* r system and a l */ - $"6963 656E 7365 6520 6361 6E6E 6F74 0D69" /* icensee cannot.i */ - $"6D70 6F73 6520 7468 6174 2063 686F 6963" /* mpose that choic */ - $"652E 0D0D 5468 6973 2073 6563 7469 6F6E" /* e...This section */ - $"2069 7320 696E 7465 6E64 6564 2074 6F20" /* is intended to */ - $"6D61 6B65 2074 686F 726F 7567 686C 7920" /* make thoroughly */ - $"636C 6561 7220 7768 6174 2069 7320 6265" /* clear what is be */ - $"6C69 6576 6564 2074 6F0D 6265 2061 2063" /* lieved to.be a c */ - $"6F6E 7365 7175 656E 6365 206F 6620 7468" /* onsequence of th */ - $"6520 7265 7374 206F 6620 7468 6973 204C" /* e rest of this L */ - $"6963 656E 7365 2E0D 0C0D 2020 382E 2049" /* icense.... 8. I */ - $"6620 7468 6520 6469 7374 7269 6275 7469" /* f the distributi */ - $"6F6E 2061 6E64 2F6F 7220 7573 6520 6F66" /* on and/or use of */ - $"2074 6865 2050 726F 6772 616D 2069 7320" /* the Program is */ - $"7265 7374 7269 6374 6564 2069 6E0D 6365" /* restricted in.ce */ - $"7274 6169 6E20 636F 756E 7472 6965 7320" /* rtain countries */ - $"6569 7468 6572 2062 7920 7061 7465 6E74" /* either by patent */ - $"7320 6F72 2062 7920 636F 7079 7269 6768" /* s or by copyrigh */ - $"7465 6420 696E 7465 7266 6163 6573 2C20" /* ted interfaces, */ - $"7468 650D 6F72 6967 696E 616C 2063 6F70" /* the.original cop */ - $"7972 6967 6874 2068 6F6C 6465 7220 7768" /* yright holder wh */ - $"6F20 706C 6163 6573 2074 6865 2050 726F" /* o places the Pro */ - $"6772 616D 2075 6E64 6572 2074 6869 7320" /* gram under this */ - $"4C69 6365 6E73 650D 6D61 7920 6164 6420" /* License.may add */ - $"616E 2065 7870 6C69 6369 7420 6765 6F67" /* an explicit geog */ - $"7261 7068 6963 616C 2064 6973 7472 6962" /* raphical distrib */ - $"7574 696F 6E20 6C69 6D69 7461 7469 6F6E" /* ution limitation */ - $"2065 7863 6C75 6469 6E67 0D74 686F 7365" /* excluding.those */ - $"2063 6F75 6E74 7269 6573 2C20 736F 2074" /* countries, so t */ - $"6861 7420 6469 7374 7269 6275 7469 6F6E" /* hat distribution */ - $"2069 7320 7065 726D 6974 7465 6420 6F6E" /* is permitted on */ - $"6C79 2069 6E20 6F72 2061 6D6F 6E67 0D63" /* ly in or among.c */ - $"6F75 6E74 7269 6573 206E 6F74 2074 6875" /* ountries not thu */ - $"7320 6578 636C 7564 6564 2E20 2049 6E20" /* s excluded. In */ - $"7375 6368 2063 6173 652C 2074 6869 7320" /* such case, this */ - $"4C69 6365 6E73 6520 696E 636F 7270 6F72" /* License incorpor */ - $"6174 6573 0D74 6865 206C 696D 6974 6174" /* ates.the limitat */ - $"696F 6E20 6173 2069 6620 7772 6974 7465" /* ion as if writte */ - $"6E20 696E 2074 6865 2062 6F64 7920 6F66" /* n in the body of */ - $"2074 6869 7320 4C69 6365 6E73 652E 0D0D" /* this License... */ - $"2020 392E 2054 6865 2046 7265 6520 536F" /* 9. The Free So */ - $"6674 7761 7265 2046 6F75 6E64 6174 696F" /* ftware Foundatio */ - $"6E20 6D61 7920 7075 626C 6973 6820 7265" /* n may publish re */ - $"7669 7365 6420 616E 642F 6F72 206E 6577" /* vised and/or new */ - $"2076 6572 7369 6F6E 730D 6F66 2074 6865" /* versions.of the */ - $"2047 656E 6572 616C 2050 7562 6C69 6320" /* General Public */ - $"4C69 6365 6E73 6520 6672 6F6D 2074 696D" /* License from tim */ - $"6520 746F 2074 696D 652E 2020 5375 6368" /* e to time. Such */ - $"206E 6577 2076 6572 7369 6F6E 7320 7769" /* new versions wi */ - $"6C6C 0D62 6520 7369 6D69 6C61 7220 696E" /* ll.be similar in */ - $"2073 7069 7269 7420 746F 2074 6865 2070" /* spirit to the p */ - $"7265 7365 6E74 2076 6572 7369 6F6E 2C20" /* resent version, */ - $"6275 7420 6D61 7920 6469 6666 6572 2069" /* but may differ i */ - $"6E20 6465 7461 696C 2074 6F0D 6164 6472" /* n detail to.addr */ - $"6573 7320 6E65 7720 7072 6F62 6C65 6D73" /* ess new problems */ - $"206F 7220 636F 6E63 6572 6E73 2E0D 0D45" /* or concerns...E */ - $"6163 6820 7665 7273 696F 6E20 6973 2067" /* ach version is g */ - $"6976 656E 2061 2064 6973 7469 6E67 7569" /* iven a distingui */ - $"7368 696E 6720 7665 7273 696F 6E20 6E75" /* shing version nu */ - $"6D62 6572 2E20 2049 6620 7468 6520 5072" /* mber. If the Pr */ - $"6F67 7261 6D0D 7370 6563 6966 6965 7320" /* ogram.specifies */ - $"6120 7665 7273 696F 6E20 6E75 6D62 6572" /* a version number */ - $"206F 6620 7468 6973 204C 6963 656E 7365" /* of this License */ - $"2077 6869 6368 2061 7070 6C69 6573 2074" /* which applies t */ - $"6F20 6974 2061 6E64 2022 616E 790D 6C61" /* o it and "any.la */ - $"7465 7220 7665 7273 696F 6E22 2C20 796F" /* ter version", yo */ - $"7520 6861 7665 2074 6865 206F 7074 696F" /* u have the optio */ - $"6E20 6F66 2066 6F6C 6C6F 7769 6E67 2074" /* n of following t */ - $"6865 2074 6572 6D73 2061 6E64 2063 6F6E" /* he terms and con */ - $"6469 7469 6F6E 730D 6569 7468 6572 206F" /* ditions.either o */ - $"6620 7468 6174 2076 6572 7369 6F6E 206F" /* f that version o */ - $"7220 6F66 2061 6E79 206C 6174 6572 2076" /* r of any later v */ - $"6572 7369 6F6E 2070 7562 6C69 7368 6564" /* ersion published */ - $"2062 7920 7468 6520 4672 6565 0D53 6F66" /* by the Free.Sof */ - $"7477 6172 6520 466F 756E 6461 7469 6F6E" /* tware Foundation */ - $"2E20 2049 6620 7468 6520 5072 6F67 7261" /* . If the Progra */ - $"6D20 646F 6573 206E 6F74 2073 7065 6369" /* m does not speci */ - $"6679 2061 2076 6572 7369 6F6E 206E 756D" /* fy a version num */ - $"6265 7220 6F66 0D74 6869 7320 4C69 6365" /* ber of.this Lice */ - $"6E73 652C 2079 6F75 206D 6179 2063 686F" /* nse, you may cho */ - $"6F73 6520 616E 7920 7665 7273 696F 6E20" /* ose any version */ - $"6576 6572 2070 7562 6C69 7368 6564 2062" /* ever published b */ - $"7920 7468 6520 4672 6565 2053 6F66 7477" /* y the Free Softw */ - $"6172 650D 466F 756E 6461 7469 6F6E 2E0D" /* are.Foundation.. */ - $"0D20 2031 302E 2049 6620 796F 7520 7769" /* . 10. If you wi */ - $"7368 2074 6F20 696E 636F 7270 6F72 6174" /* sh to incorporat */ - $"6520 7061 7274 7320 6F66 2074 6865 2050" /* e parts of the P */ - $"726F 6772 616D 2069 6E74 6F20 6F74 6865" /* rogram into othe */ - $"7220 6672 6565 0D70 726F 6772 616D 7320" /* r free.programs */ - $"7768 6F73 6520 6469 7374 7269 6275 7469" /* whose distributi */ - $"6F6E 2063 6F6E 6469 7469 6F6E 7320 6172" /* on conditions ar */ - $"6520 6469 6666 6572 656E 742C 2077 7269" /* e different, wri */ - $"7465 2074 6F20 7468 6520 6175 7468 6F72" /* te to the author */ - $"0D74 6F20 6173 6B20 666F 7220 7065 726D" /* .to ask for perm */ - $"6973 7369 6F6E 2E20 2046 6F72 2073 6F66" /* ission. For sof */ - $"7477 6172 6520 7768 6963 6820 6973 2063" /* tware which is c */ - $"6F70 7972 6967 6874 6564 2062 7920 7468" /* opyrighted by th */ - $"6520 4672 6565 0D53 6F66 7477 6172 6520" /* e Free.Software */ - $"466F 756E 6461 7469 6F6E 2C20 7772 6974" /* Foundation, writ */ - $"6520 746F 2074 6865 2046 7265 6520 536F" /* e to the Free So */ - $"6674 7761 7265 2046 6F75 6E64 6174 696F" /* ftware Foundatio */ - $"6E3B 2077 6520 736F 6D65 7469 6D65 730D" /* n; we sometimes. */ - $"6D61 6B65 2065 7863 6570 7469 6F6E 7320" /* make exceptions */ - $"666F 7220 7468 6973 2E20 204F 7572 2064" /* for this. Our d */ - $"6563 6973 696F 6E20 7769 6C6C 2062 6520" /* ecision will be */ - $"6775 6964 6564 2062 7920 7468 6520 7477" /* guided by the tw */ - $"6F20 676F 616C 730D 6F66 2070 7265 7365" /* o goals.of prese */ - $"7276 696E 6720 7468 6520 6672 6565 2073" /* rving the free s */ - $"7461 7475 7320 6F66 2061 6C6C 2064 6572" /* tatus of all der */ - $"6976 6174 6976 6573 206F 6620 6F75 7220" /* ivatives of our */ - $"6672 6565 2073 6F66 7477 6172 6520 616E" /* free software an */ - $"640D 6F66 2070 726F 6D6F 7469 6E67 2074" /* d.of promoting t */ - $"6865 2073 6861 7269 6E67 2061 6E64 2072" /* he sharing and r */ - $"6575 7365 206F 6620 736F 6674 7761 7265" /* euse of software */ - $"2067 656E 6572 616C 6C79 2E0D 0D09 0909" /* generally...ÆÆÆ */ - $"2020 2020 4E4F 2057 4152 5241 4E54 590D" /* NO WARRANTY. */ - $"0D20 2031 312E 2042 4543 4155 5345 2054" /* . 11. BECAUSE T */ - $"4845 2050 524F 4752 414D 2049 5320 4C49" /* HE PROGRAM IS LI */ - $"4345 4E53 4544 2046 5245 4520 4F46 2043" /* CENSED FREE OF C */ - $"4841 5247 452C 2054 4845 5245 2049 5320" /* HARGE, THERE IS */ - $"4E4F 2057 4152 5241 4E54 590D 464F 5220" /* NO WARRANTY.FOR */ - $"5448 4520 5052 4F47 5241 4D2C 2054 4F20" /* THE PROGRAM, TO */ - $"5448 4520 4558 5445 4E54 2050 4552 4D49" /* THE EXTENT PERMI */ - $"5454 4544 2042 5920 4150 504C 4943 4142" /* TTED BY APPLICAB */ - $"4C45 204C 4157 2E20 2045 5843 4550 5420" /* LE LAW. EXCEPT */ - $"5748 454E 0D4F 5448 4552 5749 5345 2053" /* WHEN.OTHERWISE S */ - $"5441 5445 4420 494E 2057 5249 5449 4E47" /* TATED IN WRITING */ - $"2054 4845 2043 4F50 5952 4947 4854 2048" /* THE COPYRIGHT H */ - $"4F4C 4445 5253 2041 4E44 2F4F 5220 4F54" /* OLDERS AND/OR OT */ - $"4845 5220 5041 5254 4945 530D 5052 4F56" /* HER PARTIES.PROV */ - $"4944 4520 5448 4520 5052 4F47 5241 4D20" /* IDE THE PROGRAM */ - $"2241 5320 4953 2220 5749 5448 4F55 5420" /* "AS IS" WITHOUT */ - $"5741 5252 414E 5459 204F 4620 414E 5920" /* WARRANTY OF ANY */ - $"4B49 4E44 2C20 4549 5448 4552 2045 5850" /* KIND, EITHER EXP */ - $"5245 5353 4544 0D4F 5220 494D 504C 4945" /* RESSED.OR IMPLIE */ - $"442C 2049 4E43 4C55 4449 4E47 2C20 4255" /* D, INCLUDING, BU */ - $"5420 4E4F 5420 4C49 4D49 5445 4420 544F" /* T NOT LIMITED TO */ - $"2C20 5448 4520 494D 504C 4945 4420 5741" /* , THE IMPLIED WA */ - $"5252 414E 5449 4553 204F 460D 4D45 5243" /* RRANTIES OF.MERC */ - $"4841 4E54 4142 494C 4954 5920 414E 4420" /* HANTABILITY AND */ - $"4649 544E 4553 5320 464F 5220 4120 5041" /* FITNESS FOR A PA */ - $"5254 4943 554C 4152 2050 5552 504F 5345" /* RTICULAR PURPOSE */ - $"2E20 2054 4845 2045 4E54 4952 4520 5249" /* . THE ENTIRE RI */ - $"534B 2041 530D 544F 2054 4845 2051 5541" /* SK AS.TO THE QUA */ - $"4C49 5459 2041 4E44 2050 4552 464F 524D" /* LITY AND PERFORM */ - $"414E 4345 204F 4620 5448 4520 5052 4F47" /* ANCE OF THE PROG */ - $"5241 4D20 4953 2057 4954 4820 594F 552E" /* RAM IS WITH YOU. */ - $"2020 5348 4F55 4C44 2054 4845 0D50 524F" /* SHOULD THE.PRO */ - $"4752 414D 2050 524F 5645 2044 4546 4543" /* GRAM PROVE DEFEC */ - $"5449 5645 2C20 594F 5520 4153 5355 4D45" /* TIVE, YOU ASSUME */ - $"2054 4845 2043 4F53 5420 4F46 2041 4C4C" /* THE COST OF ALL */ - $"204E 4543 4553 5341 5259 2053 4552 5649" /* NECESSARY SERVI */ - $"4349 4E47 2C0D 5245 5041 4952 204F 5220" /* CING,.REPAIR OR */ - $"434F 5252 4543 5449 4F4E 2E0D 0D20 2031" /* CORRECTION... 1 */ - $"322E 2049 4E20 4E4F 2045 5645 4E54 2055" /* 2. IN NO EVENT U */ - $"4E4C 4553 5320 5245 5155 4952 4544 2042" /* NLESS REQUIRED B */ - $"5920 4150 504C 4943 4142 4C45 204C 4157" /* Y APPLICABLE LAW */ - $"204F 5220 4147 5245 4544 2054 4F20 494E" /* OR AGREED TO IN */ - $"2057 5249 5449 4E47 0D57 494C 4C20 414E" /* WRITING.WILL AN */ - $"5920 434F 5059 5249 4748 5420 484F 4C44" /* Y COPYRIGHT HOLD */ - $"4552 2C20 4F52 2041 4E59 204F 5448 4552" /* ER, OR ANY OTHER */ - $"2050 4152 5459 2057 484F 204D 4159 204D" /* PARTY WHO MAY M */ - $"4F44 4946 5920 414E 442F 4F52 0D52 4544" /* ODIFY AND/OR.RED */ - $"4953 5452 4942 5554 4520 5448 4520 5052" /* ISTRIBUTE THE PR */ - $"4F47 5241 4D20 4153 2050 4552 4D49 5454" /* OGRAM AS PERMITT */ - $"4544 2041 424F 5645 2C20 4245 204C 4941" /* ED ABOVE, BE LIA */ - $"424C 4520 544F 2059 4F55 2046 4F52 2044" /* BLE TO YOU FOR D */ - $"414D 4147 4553 2C0D 494E 434C 5544 494E" /* AMAGES,.INCLUDIN */ - $"4720 414E 5920 4745 4E45 5241 4C2C 2053" /* G ANY GENERAL, S */ - $"5045 4349 414C 2C20 494E 4349 4445 4E54" /* PECIAL, INCIDENT */ - $"414C 204F 5220 434F 4E53 4551 5545 4E54" /* AL OR CONSEQUENT */ - $"4941 4C20 4441 4D41 4745 5320 4152 4953" /* IAL DAMAGES ARIS */ - $"494E 470D 4F55 5420 4F46 2054 4845 2055" /* ING.OUT OF THE U */ - $"5345 204F 5220 494E 4142 494C 4954 5920" /* SE OR INABILITY */ - $"544F 2055 5345 2054 4845 2050 524F 4752" /* TO USE THE PROGR */ - $"414D 2028 494E 434C 5544 494E 4720 4255" /* AM (INCLUDING BU */ - $"5420 4E4F 5420 4C49 4D49 5445 440D 544F" /* T NOT LIMITED.TO */ - $"204C 4F53 5320 4F46 2044 4154 4120 4F52" /* LOSS OF DATA OR */ - $"2044 4154 4120 4245 494E 4720 5245 4E44" /* DATA BEING REND */ - $"4552 4544 2049 4E41 4343 5552 4154 4520" /* ERED INACCURATE */ - $"4F52 204C 4F53 5345 5320 5355 5354 4149" /* OR LOSSES SUSTAI */ - $"4E45 4420 4259 0D59 4F55 204F 5220 5448" /* NED BY.YOU OR TH */ - $"4952 4420 5041 5254 4945 5320 4F52 2041" /* IRD PARTIES OR A */ - $"2046 4149 4C55 5245 204F 4620 5448 4520" /* FAILURE OF THE */ - $"5052 4F47 5241 4D20 544F 204F 5045 5241" /* PROGRAM TO OPERA */ - $"5445 2057 4954 4820 414E 5920 4F54 4845" /* TE WITH ANY OTHE */ - $"520D 5052 4F47 5241 4D53 292C 2045 5645" /* R.PROGRAMS), EVE */ - $"4E20 4946 2053 5543 4820 484F 4C44 4552" /* N IF SUCH HOLDER */ - $"204F 5220 4F54 4845 5220 5041 5254 5920" /* OR OTHER PARTY */ - $"4841 5320 4245 454E 2041 4456 4953 4544" /* HAS BEEN ADVISED */ - $"204F 4620 5448 450D 504F 5353 4942 494C" /* OF THE.POSSIBIL */ - $"4954 5920 4F46 2053 5543 4820 4441 4D41" /* ITY OF SUCH DAMA */ - $"4745 532E 0D0D 0909 2020 2020 2045 4E44" /* GES...ÆÆ END */ - $"204F 4620 5445 524D 5320 414E 4420 434F" /* OF TERMS AND CO */ - $"4E44 4954 494F 4E53 0D0C 0D09 2020 2020" /* NDITIONS...Æ */ - $"486F 7720 746F 2041 7070 6C79 2054 6865" /* How to Apply The */ - $"7365 2054 6572 6D73 2074 6F20 596F 7572" /* se Terms to Your */ - $"204E 6577 2050 726F 6772 616D 730D 0D20" /* New Programs.. */ - $"2049 6620 796F 7520 6465 7665 6C6F 7020" /* If you develop */ - $"6120 6E65 7720 7072 6F67 7261 6D2C 2061" /* a new program, a */ - $"6E64 2079 6F75 2077 616E 7420 6974 2074" /* nd you want it t */ - $"6F20 6265 206F 6620 7468 6520 6772 6561" /* o be of the grea */ - $"7465 7374 0D70 6F73 7369 626C 6520 7573" /* test.possible us */ - $"6520 746F 2074 6865 2070 7562 6C69 632C" /* e to the public, */ - $"2074 6865 2062 6573 7420 7761 7920 746F" /* the best way to */ - $"2061 6368 6965 7665 2074 6869 7320 6973" /* achieve this is */ - $"2074 6F20 6D61 6B65 2069 740D 6672 6565" /* to make it.free */ - $"2073 6F66 7477 6172 6520 7768 6963 6820" /* software which */ - $"6576 6572 796F 6E65 2063 616E 2072 6564" /* everyone can red */ - $"6973 7472 6962 7574 6520 616E 6420 6368" /* istribute and ch */ - $"616E 6765 2075 6E64 6572 2074 6865 7365" /* ange under these */ - $"2074 6572 6D73 2E0D 0D20 2054 6F20 646F" /* terms... To do */ - $"2073 6F2C 2061 7474 6163 6820 7468 6520" /* so, attach the */ - $"666F 6C6C 6F77 696E 6720 6E6F 7469 6365" /* following notice */ - $"7320 746F 2074 6865 2070 726F 6772 616D" /* s to the program */ - $"2E20 2049 7420 6973 2073 6166 6573 740D" /* . It is safest. */ - $"746F 2061 7474 6163 6820 7468 656D 2074" /* to attach them t */ - $"6F20 7468 6520 7374 6172 7420 6F66 2065" /* o the start of e */ - $"6163 6820 736F 7572 6365 2066 696C 6520" /* ach source file */ - $"746F 206D 6F73 7420 6566 6665 6374 6976" /* to most effectiv */ - $"656C 790D 636F 6E76 6579 2074 6865 2065" /* ely.convey the e */ - $"7863 6C75 7369 6F6E 206F 6620 7761 7272" /* xclusion of warr */ - $"616E 7479 3B20 616E 6420 6561 6368 2066" /* anty; and each f */ - $"696C 6520 7368 6F75 6C64 2068 6176 6520" /* ile should have */ - $"6174 206C 6561 7374 0D74 6865 2022 636F" /* at least.the "co */ - $"7079 7269 6768 7422 206C 696E 6520 616E" /* pyright" line an */ - $"6420 6120 706F 696E 7465 7220 746F 2077" /* d a pointer to w */ - $"6865 7265 2074 6865 2066 756C 6C20 6E6F" /* here the full no */ - $"7469 6365 2069 7320 666F 756E 642E 0D0D" /* tice is found... */ - $"2020 2020 3C6F 6E65 206C 696E 6520 746F" /* . */ - $"436F 7079 7269 6768 7420 2843 2920 3139" /* Copyright (C) 19 */ - $"7979 2020 3C6E 616D 6520 6F66 2061 7574" /* yy .. This p */ - $"726F 6772 616D 2069 7320 6672 6565 2073" /* rogram is free s */ - $"6F66 7477 6172 653B 2079 6F75 2063 616E" /* oftware; you can */ - $"2072 6564 6973 7472 6962 7574 6520 6974" /* redistribute it */ - $"2061 6E64 2F6F 7220 6D6F 6469 6679 0D20" /* and/or modify. */ - $"2020 2069 7420 756E 6465 7220 7468 6520" /* it under the */ - $"7465 726D 7320 6F66 2074 6865 2047 4E55" /* terms of the GNU */ - $"2047 656E 6572 616C 2050 7562 6C69 6320" /* General Public */ - $"4C69 6365 6E73 6520 6173 2070 7562 6C69" /* License as publi */ - $"7368 6564 2062 790D 2020 2020 7468 6520" /* shed by. the */ - $"4672 6565 2053 6F66 7477 6172 6520 466F" /* Free Software Fo */ - $"756E 6461 7469 6F6E 3B20 6569 7468 6572" /* undation; either */ - $"2076 6572 7369 6F6E 2032 206F 6620 7468" /* version 2 of th */ - $"6520 4C69 6365 6E73 652C 206F 720D 2020" /* e License, or. */ - $"2020 2861 7420 796F 7572 206F 7074 696F" /* (at your optio */ - $"6E29 2061 6E79 206C 6174 6572 2076 6572" /* n) any later ver */ - $"7369 6F6E 2E0D 0D20 2020 2054 6869 7320" /* sion... This */ - $"7072 6F67 7261 6D20 6973 2064 6973 7472" /* program is distr */ - $"6962 7574 6564 2069 6E20 7468 6520 686F" /* ibuted in the ho */ - $"7065 2074 6861 7420 6974 2077 696C 6C20" /* pe that it will */ - $"6265 2075 7365 6675 6C2C 0D20 2020 2062" /* be useful,. b */ - $"7574 2057 4954 484F 5554 2041 4E59 2057" /* ut WITHOUT ANY W */ - $"4152 5241 4E54 593B 2077 6974 686F 7574" /* ARRANTY; without */ - $"2065 7665 6E20 7468 6520 696D 706C 6965" /* even the implie */ - $"6420 7761 7272 616E 7479 206F 660D 2020" /* d warranty of. */ - $"2020 4D45 5243 4841 4E54 4142 494C 4954" /* MERCHANTABILIT */ - $"5920 6F72 2046 4954 4E45 5353 2046 4F52" /* Y or FITNESS FOR */ - $"2041 2050 4152 5449 4355 4C41 5220 5055" /* A PARTICULAR PU */ - $"5250 4F53 452E 2020 5365 6520 7468 650D" /* RPOSE. See the. */ - $"2020 2020 474E 5520 4765 6E65 7261 6C20" /* GNU General */ - $"5075 626C 6963 204C 6963 656E 7365 2066" /* Public License f */ - $"6F72 206D 6F72 6520 6465 7461 696C 732E" /* or more details. */ - $"0D0D 2020 2020 596F 7520 7368 6F75 6C64" /* .. You should */ - $"2068 6176 6520 7265 6365 6976 6564 2061" /* have received a */ - $"2063 6F70 7920 6F66 2074 6865 2047 4E55" /* copy of the GNU */ - $"2047 656E 6572 616C 2050 7562 6C69 6320" /* General Public */ - $"4C69 6365 6E73 650D 2020 2020 616C 6F6E" /* License. alon */ - $"6720 7769 7468 2074 6869 7320 7072 6F67" /* g with this prog */ - $"7261 6D3B 2069 6620 6E6F 742C 2077 7269" /* ram; if not, wri */ - $"7465 2074 6F20 7468 6520 4672 6565 2053" /* te to the Free S */ - $"6F66 7477 6172 650D 2020 2020 466F 756E" /* oftware. Foun */ - $"6461 7469 6F6E 2C20 496E 632E 2C20 3539" /* dation, Inc., 59 */ - $"2054 656D 706C 6520 506C 6163 652C 2053" /* Temple Place, S */ - $"7569 7465 2033 3330 2C20 426F 7374 6F6E" /* uite 330, Boston */ - $"2C20 4D41 2020 3032 3131 312D 3133 3037" /* , MA 02111-1307 */ - $"2020 5553 410D 0D0D 416C 736F 2061 6464" /* USA...Also add */ - $"2069 6E66 6F72 6D61 7469 6F6E 206F 6E20" /* information on */ - $"686F 7720 746F 2063 6F6E 7461 6374 2079" /* how to contact y */ - $"6F75 2062 7920 656C 6563 7472 6F6E 6963" /* ou by electronic */ - $"2061 6E64 2070 6170 6572 206D 6169 6C2E" /* and paper mail. */ - $"0D0D 4966 2074 6865 2070 726F 6772 616D" /* ..If the program */ - $"2069 7320 696E 7465 7261 6374 6976 652C" /* is interactive, */ - $"206D 616B 6520 6974 206F 7574 7075 7420" /* make it output */ - $"6120 7368 6F72 7420 6E6F 7469 6365 206C" /* a short notice l */ - $"696B 6520 7468 6973 0D77 6865 6E20 6974" /* ike this.when it */ - $"2073 7461 7274 7320 696E 2061 6E20 696E" /* starts in an in */ - $"7465 7261 6374 6976 6520 6D6F 6465 3A0D" /* teractive mode:. */ - $"0D20 2020 2047 6E6F 6D6F 7669 7369 6F6E" /* . Gnomovision */ - $"2076 6572 7369 6F6E 2036 392C 2043 6F70" /* version 69, Cop */ - $"7972 6967 6874 2028 4329 2031 3979 7920" /* yright (C) 19yy */ - $"6E61 6D65 206F 6620 6175 7468 6F72 0D20" /* name of author. */ - $"2020 2047 6E6F 6D6F 7669 7369 6F6E 2063" /* Gnomovision c */ - $"6F6D 6573 2077 6974 6820 4142 534F 4C55" /* omes with ABSOLU */ - $"5445 4C59 204E 4F20 5741 5252 414E 5459" /* TELY NO WARRANTY */ - $"3B20 666F 7220 6465 7461 696C 7320 7479" /* ; for details ty */ - $"7065 2060 7368 6F77 2077 272E 0D20 2020" /* pe `show w'.. */ - $"2054 6869 7320 6973 2066 7265 6520 736F" /* This is free so */ - $"6674 7761 7265 2C20 616E 6420 796F 7520" /* ftware, and you */ - $"6172 6520 7765 6C63 6F6D 6520 746F 2072" /* are welcome to r */ - $"6564 6973 7472 6962 7574 6520 6974 0D20" /* edistribute it. */ - $"2020 2075 6E64 6572 2063 6572 7461 696E" /* under certain */ - $"2063 6F6E 6469 7469 6F6E 733B 2074 7970" /* conditions; typ */ - $"6520 6073 686F 7720 6327 2066 6F72 2064" /* e `show c' for d */ - $"6574 6169 6C73 2E0D 0D54 6865 2068 7970" /* etails...The hyp */ - $"6F74 6865 7469 6361 6C20 636F 6D6D 616E" /* othetical comman */ - $"6473 2060 7368 6F77 2077 2720 616E 6420" /* ds `show w' and */ - $"6073 686F 7720 6327 2073 686F 756C 6420" /* `show c' should */ - $"7368 6F77 2074 6865 2061 7070 726F 7072" /* show the appropr */ - $"6961 7465 0D70 6172 7473 206F 6620 7468" /* iate.parts of th */ - $"6520 4765 6E65 7261 6C20 5075 626C 6963" /* e General Public */ - $"204C 6963 656E 7365 2E20 204F 6620 636F" /* License. Of co */ - $"7572 7365 2C20 7468 6520 636F 6D6D 616E" /* urse, the comman */ - $"6473 2079 6F75 2075 7365 206D 6179 0D62" /* ds you use may.b */ - $"6520 6361 6C6C 6564 2073 6F6D 6574 6869" /* e called somethi */ - $"6E67 206F 7468 6572 2074 6861 6E20 6073" /* ng other than `s */ - $"686F 7720 7727 2061 6E64 2060 7368 6F77" /* how w' and `show */ - $"2063 273B 2074 6865 7920 636F 756C 6420" /* c'; they could */ - $"6576 656E 2062 650D 6D6F 7573 652D 636C" /* even be.mouse-cl */ - $"6963 6B73 206F 7220 6D65 6E75 2069 7465" /* icks or menu ite */ - $"6D73 2D2D 7768 6174 6576 6572 2073 7569" /* ms--whatever sui */ - $"7473 2079 6F75 7220 7072 6F67 7261 6D2E" /* ts your program. */ - $"0D0D 596F 7520 7368 6F75 6C64 2061 6C73" /* ..You should als */ - $"6F20 6765 7420 796F 7572 2065 6D70 6C6F" /* o get your emplo */ - $"7965 7220 2869 6620 796F 7520 776F 726B" /* yer (if you work */ - $"2061 7320 6120 7072 6F67 7261 6D6D 6572" /* as a programmer */ - $"2920 6F72 2079 6F75 720D 7363 686F 6F6C" /* ) or your.school */ - $"2C20 6966 2061 6E79 2C20 746F 2073 6967" /* , if any, to sig */ - $"6E20 6120 2263 6F70 7972 6967 6874 2064" /* n a "copyright d */ - $"6973 636C 6169 6D65 7222 2066 6F72 2074" /* isclaimer" for t */ - $"6865 2070 726F 6772 616D 2C20 6966 0D6E" /* he program, if.n */ - $"6563 6573 7361 7279 2E20 2048 6572 6520" /* ecessary. Here */ - $"6973 2061 2073 616D 706C 653B 2061 6C74" /* is a sample; alt */ - $"6572 2074 6865 206E 616D 6573 3A0D 0D20" /* er the names:.. */ - $"2059 6F79 6F64 796E 652C 2049 6E63 2E2C" /* Yoyodyne, Inc., */ - $"2068 6572 6562 7920 6469 7363 6C61 696D" /* hereby disclaim */ - $"7320 616C 6C20 636F 7079 7269 6768 7420" /* s all copyright */ - $"696E 7465 7265 7374 2069 6E20 7468 6520" /* interest in the */ - $"7072 6F67 7261 6D0D 2020 6047 6E6F 6D6F" /* program. `Gnomo */ - $"7669 7369 6F6E 2720 2877 6869 6368 206D" /* vision' (which m */ - $"616B 6573 2070 6173 7365 7320 6174 2063" /* akes passes at c */ - $"6F6D 7069 6C65 7273 2920 7772 6974 7465" /* ompilers) writte */ - $"6E20 6279 204A 616D 6573 2048 6163 6B65" /* n by James Hacke */ - $"722E 0D0D 2020 3C73 6967 6E61 7475 7265" /* r... , 1 */ - $"4170 7269 6C20 3139 3839 0D20 2054 7920" /* April 1989. Ty */ - $"436F 6F6E 2C20 5072 6573 6964 656E 7420" /* Coon, President */ - $"6F66 2056 6963 650D 0D54 6869 7320 4765" /* of Vice..This Ge */ - $"6E65 7261 6C20 5075 626C 6963 204C 6963" /* neral Public Lic */ - $"656E 7365 2064 6F65 7320 6E6F 7420 7065" /* ense does not pe */ - $"726D 6974 2069 6E63 6F72 706F 7261 7469" /* rmit incorporati */ - $"6E67 2079 6F75 7220 7072 6F67 7261 6D20" /* ng your program */ - $"696E 746F 0D70 726F 7072 6965 7461 7279" /* into.proprietary */ - $"2070 726F 6772 616D 732E 2020 4966 2079" /* programs. If y */ - $"6F75 7220 7072 6F67 7261 6D20 6973 2061" /* our program is a */ - $"2073 7562 726F 7574 696E 6520 6C69 6272" /* subroutine libr */ - $"6172 792C 2079 6F75 206D 6179 0D63 6F6E" /* ary, you may.con */ - $"7369 6465 7220 6974 206D 6F72 6520 7573" /* sider it more us */ - $"6566 756C 2074 6F20 7065 726D 6974 206C" /* eful to permit l */ - $"696E 6B69 6E67 2070 726F 7072 6965 7461" /* inking proprieta */ - $"7279 2061 7070 6C69 6361 7469 6F6E 7320" /* ry applications */ - $"7769 7468 2074 6865 0D6C 6962 7261 7279" /* with the.library */ - $"2E20 2049 6620 7468 6973 2069 7320 7768" /* . If this is wh */ - $"6174 2079 6F75 2077 616E 7420 746F 2064" /* at you want to d */ - $"6F2C 2075 7365 2074 6865 2047 4E55 204C" /* o, use the GNU L */ - $"6962 7261 7279 2047 656E 6572 616C 0D50" /* ibrary General.P */ - $"7562 6C69 6320 4C69 6365 6E73 6520 696E" /* ublic License in */ - $"7374 6561 6420 6F66 2074 6869 7320 4C69" /* stead of this Li */ - $"6365 6E73 652E 0D" /* cense.. */ -}; - -data 'LPic' (5000) { - $"0000 0001 0000 0000 0000" /* .......... */ -}; - -data 'styl' (5000, "English") { - $"0001 0000 0000 000C 0009 0015 0030 000C" /* .........Æ...0.. */ - $"0000 0000 0000" /* ...... */ -}; diff --git a/MacBuild/HOWTO b/MacBuild/HOWTO deleted file mode 100644 index 184b51b..0000000 --- a/MacBuild/HOWTO +++ /dev/null @@ -1,18 +0,0 @@ -Don't. - -If you still want to, here's my terse step by step guide. I only know that this works in Snow Leopard on my mac. It might not work for you. -1) Get python 2.6 from http://www.python.org/ftp/python/2.5.6/Python-2.5.6.tgz -2) Compile it, using configure_python.sh in this directory. It expects to be placed one directory up from python, simply because I compiled everything from ~/python_compile/ -3) export PATH=/Library/Frameworks/Python.framework/Versions/2.6/bin/:$PATH for both you and root. Confirm with `which python` -4) sudo su; easy_install pygame; easy_install py2app -5) Get the QT library from http://qt.nokia.com/downloads/qt-for-open-source-cpp-development-on-mac-os-x/. Do not even consider - trying to compile this whore of a library yourself, it's not worth it. Get the precompiled for your system. Install it. -6) Get SIP from http://www.riverbankcomputing.co.uk/software/sip/download and compile it, making sure to use configure_sip.sh. -7) Get PyQt4 from http://www.riverbankcomputing.co.uk/software/pyqt/download and compile it, also with my configure script (configure_pyqt4.sh). This will take ages. -8) ./py2app.sh and wait for it to build everything and make itself into a purdy DMG -9) Rejoice that you didn't have to spend two weeks compiling hundreds of versions of all things mentioned here, including an entire day simply waiting for QT to compile by - itself on the offchance that this would make it work. - -If you want to make a nicer looking dmg file, play with dmg_background.png - -~Lex diff --git a/MacBuild/configure_pyqt4.sh b/MacBuild/configure_pyqt4.sh deleted file mode 100755 index ade4b0c..0000000 --- a/MacBuild/configure_pyqt4.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -echo "Lexi's lazy configuration. This is not an official configure script. Press enter to confirm this." -read confirm -if [ ! -d pyqt4 ] -then - echo "Rename your pyqt4 folder to pyqt4." - exit 1 -fi -cd pyqt4 -if [ -e makefile ] -then - make clean -fi -python configure.py \ - --confirm-license \ - --use-arch=i386 \ - --use-arch=x86_64 \ - --destdir=/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages \ - --verbose -echo "---~ Done ~---" diff --git a/MacBuild/configure_python.sh b/MacBuild/configure_python.sh deleted file mode 100755 index 3ecb051..0000000 --- a/MacBuild/configure_python.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Lexi's ./configure script -# -echo "Lexi's lazy configuration. This is not an official configure script. Press enter to confirm this." -read confirm -if [ ! -d python ] -then - echo "Rename your python folder to python." - exit 1 -fi -cd python -if [ ! -d python ] -then - echo "Rename your python folder to python." - exit 1 -fi -if [ -e makefile ] -then - make clean -fi -./configure --enable-framework --enable-universalsdk=/ --with-universal-archs=intel MACOSX_DEPLOYMENT_TARGET=10.5 -echo "---~ Done ~---" diff --git a/MacBuild/configure_sip.sh b/MacBuild/configure_sip.sh deleted file mode 100755 index e8b66a1..0000000 --- a/MacBuild/configure_sip.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# -# Lexi's Configurations -# - -echo "Lexi's lazy configuration. This is not an official configure script. Press enter to confirm this." -read confirm -if [ ! -d sip ] -then - echo "Rename your sip folder to sip." - exit 1 -fi -cd sip -if [ -e makefile ] -then - make clean -fi -python configure.py --arch=i386 --arch=x86_64 \ - --universal --deployment-target=10.5 \ - --destdir=/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/ -echo "---~ Done ~---" diff --git a/MacBuild/conv3rt.sh b/MacBuild/conv3rt.sh deleted file mode 100644 index d6656d5..0000000 --- a/MacBuild/conv3rt.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Lex's gif->png script - -for file in *.gif -do - convert ${file} ${file:0:$((${#file}-3))}"png" -done - -for file in `ls | grep -G -e "-[1-9]\+.png"` -do - rm $file -done - -for file in `ls | grep -e "-0.png"` -do - newfile=`echo $file | sed -e 's|\(.*\)-0.png|\1.png|'` - mv $file $newfile -done - -# for file in *.gif -# do -# rm ${file:0:$((${#file}-3))}"png" -# done diff --git a/MacBuild/dmg_background.png b/MacBuild/dmg_background.png deleted file mode 100644 index 236deb6..0000000 Binary files a/MacBuild/dmg_background.png and /dev/null differ diff --git a/MacBuild/dmg_background.xcf b/MacBuild/dmg_background.xcf deleted file mode 100644 index 94246a2..0000000 Binary files a/MacBuild/dmg_background.xcf and /dev/null differ diff --git a/Makefile b/Makefile deleted file mode 100644 index 7cb7398..0000000 --- a/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -PYTHON2_CMD ?= /usr/bin/python - -PREFIX ?= /usr/local -LIBINSTALLDIR ?= /lib -XDGCONFDIR ?= /etc/xdg - -PESTERCHUMBINDIR = ${DESTDIR}${PREFIX}/bin -PESTERCHUMLIBDIR = $(DESTDIR)$(PREFIX)$(LIBINSTALLDIR)/pesterchum - -all: - @echo "Ready to install..." - -make-install-dirs: - mkdir -p ${PESTERCHUMBINDIR} - mkdir -p ${PESTERCHUMLIBDIR} - mkdir -p ${PESTERCHUMLIBDIR}/libs - mkdir -p ${PESTERCHUMLIBDIR}/oyoyo - mkdir -p ${PESTERCHUMLIBDIR}/quirks - mkdir -p ${PESTERCHUMLIBDIR}/smilies - mkdir -p ${PESTERCHUMLIBDIR}/themes - -uninstall: - rm -f ${PESTERCHUMBINDIR}/pesterchum - rm -rf ${PESTERCHUMLIBDIR} - -install: make-install-dirs - install -m 644 *.py ${PESTERCHUMLIBDIR} - install -m 644 libs/*.py ${PESTERCHUMLIBDIR}/libs - install -m 644 oyoyo/*.py ${PESTERCHUMLIBDIR}/oyoyo - install -m 644 quirks/*.py ${PESTERCHUMLIBDIR}/quirks - install -m 644 smilies/* ${PESTERCHUMLIBDIR}/smilies - cp -r themes/* ${PESTERCHUMLIBDIR}/themes - @echo '#!/bin/sh' > ${PESTERCHUMBINDIR}/pesterchum - @echo 'cd ${PREFIX}$(LIBINSTALLDIR)/pesterchum' >> ${PESTERCHUMBINDIR}/pesterchum - @echo 'python2 pesterchum.py' >> ${PESTERCHUMBINDIR}/pesterchum - chmod +x ${PESTERCHUMBINDIR}/pesterchum diff --git a/PCskins.png b/PCskins.png deleted file mode 100644 index da83820..0000000 Binary files a/PCskins.png and /dev/null differ diff --git a/PYQUIRKS.mkdn b/PYQUIRKS.mkdn deleted file mode 100644 index de4eb27..0000000 --- a/PYQUIRKS.mkdn +++ /dev/null @@ -1,88 +0,0 @@ -Python Quirk Functions -=============== - -Table of Contents ------------------ -1. Introduction -2. Create A Module -3. Functions In A Module -4. Command Requirements -5. Completed Quirk Function - -Introduction ---------------- -Over the course of this short tutorial you will learn: - -* How to create your own Quirk Functions -* VERY basic Python syntax - -You will not learn: - -* How to write Python -* How to bake a cake - -Throughout this tutorial there will be -
-Instructions in special boxes.
-If you follow the instructions in these boxes, by the end of this tutorial
-you will have recreated the default reverse() Quirk Function.
-
- -Create A Module -------------------- -All Quirk Function Modules should be created in the 'quirks/' directory. File names must end in '.py'. -You can have multiple Quirk Functions per Module. - -Each Module can also have a 'setup' function which will be called once, the moment the Module is loaded. - -
-Create 'reverse.py' in the 'quirks/' directory.
-
- -Functions In A Module --------------------------- -If you've ever done programming before, you should know what a function is. If not, I suggest picking up a good programming book (or e-book). - -In Python, function syntax looks like this: - -def function_name(myvar1, myvar2): - -'def' is used to declare that this is a function, and 'function_name' is obviously the name of your function. -'myvar1' and 'myvar2' are variables coming into your function. For most of your functions, the only variable being passed will be 'text'. - -In Python, curly braces ({}) are not used to declare the beginning and end of a function. Instead, a colon (:) is used to declare the beginning of a function. After that, indentation is used to declare the body and end of a function. - -```python -def reverserep(text): - return text[::-1] -``` - -Command Requirements ------------------------- -For a function to be registered as a Quirk Function, it must conform to three simple rules: - -1. It must have a command name. -2. It must take exactly one arguement. -3. It must return a string. - -What is meant by having a command name, is that a name for the Quirk Function has to be defined. This is done by defining the 'command' variable for a function. - -function_name.command = "name" - -```python -reverserep.command = "reverse" -``` - -Completed Quirk Function ---------------------------- -Below is the completed, fully working, reverse Quirk Function. After it I will break down the pieces of each line. - -```python -def reverserep(text): - return text[::-1] -reverserep.command = "reverse" -``` - -As stated before, to start a function, you need to use the keyword 'def'. All Quirk Functions must take exactly one argument (in this case 'text'). -In this example, the text is reversed and returned all in one line. 'text[::-1]' is the Pythonic way of reversing a list or string. -The last line is the most important part. This tells Pesterchum to call this function whenever 'reverse()' is used in a quirk. diff --git a/Pesterchum.png b/Pesterchum.png deleted file mode 100644 index 4e76f52..0000000 Binary files a/Pesterchum.png and /dev/null differ diff --git a/README-karxi.mkdn b/README-karxi.mkdn deleted file mode 100644 index a2a86ce..0000000 --- a/README-karxi.mkdn +++ /dev/null @@ -1,184 +0,0 @@ -Welcome to Pesterchum 3.41! -============================= - -## FOR NEW USERS -This modification of Pesterchum is intended for people who are already familiar -with using the base client. - -If you aren't, please check the standard build's [documentation][pchum-doc]. - -[pchum-orig]: https://github.com/illuminatedwax/pesterchum -[pchum-doc]: https://github.com/illuminatedwax/pesterchum/blob/master/README.mkdn - -## FOR EVERYONE ELSE -Greetings! This is a modification of Pesterchum, made because Pesterchum is -effectively no longer maintained, that is intended to fix a number of issues. - -The code used as a base is a newer version of Pesterchum than the one in -circulation, and thus has plenty of useful features that can be found in the -[CHANGELOG][changes]. - -In addition, there are other features and improvements that have been made, and -there are many more planned. Check the [TODO list][todo-done] to see what's -been fixed, as well as what's [planned][todo-upcoming]. - -[changes]: https://github.com/karxi/pesterchum/blob/master/CHANGELOG.mkdn -[todo-done]: https://github.com/karxi/pesterchum/blob/master/TODO.mkdn#tododone -[todo-upcoming]: https://github.com/karxi/pesterchum/blob/master/TODO.mkdn#features - -### Installation -There isn't an automated installer yet, but the steps involved aren't all that -difficult. - -#### Pitfalls -* If you're on a 64-bit system (and most are these days), use those links. You - can also use the 32 bit versions, if you choose, but you *cannot* mix them. -* If you're on a 32-bit system but use the 64-bit installers, you'll get an - error along the lines of "not a valid Win32 application", or the - installer will simply fail. -* This version of Pesterchum does not come compiled as an executable, and thus - does not have Python/PyQt4 packaged with it. Those are necessary for - Pesterchum to run, so you have to install them manually. - -#### First-Time Install -Download links are for Windows, but a quick Google search will find everything -necessary. - -1. Install **Python 2.7** or higher if you don't already have it: - * [32 bit][python2-32] - * [64 bit][python2-64] - - Be **sure** to add Python to the PATH if asked to do so during - installation. It means Python will be usable from the console, - which is necessary for this to run. - -2. Install **PyQt4**: - * [32 bit][pyqt4-32] - * [64 bit][pyqt4-64] - -3. **(LINUX)** Install **pygame**: - * [pygame download page][pygame-dl] - * You don't need to install this if you're using Windows. Linux users need - to install it to enable sound, but it will otherwise work without it. - * If you want to download this, you should probably do so using your native - package manager. - -4. Download **Pesterchum**: - * [Download from main branch][pchum-zip] - -5. Unzip Pesterchum somewhere easily-accessible. - -6. **If you have any custom themes**, copy/paste them into the 'themes' folder. - You can find this in `%LOCALAPPDATA%\pesterchum`, which is the same as - `%APPDATA%\..\Local\pesterchum`. Copy/paste one into Explorer's address bar - and you'll end up where you need to be. - - Oftentimes the 'themes' folder doesn't exist in Pesterchum's user-specific - config folder, so you'll have to make it and copy the custom themes into - it. - - __If, for some reason, that doesn't work:__ - - You can also copy the missing themes into the 'themes' folder of the version - you just unzipped. **Don't overwrite any files** if you do this - the themes - used by this have been updated, and the older default themes may break when - used. - -7. Run Pesterchum! How you do this depends on the OS: - * **(WINDOWS)** Run `w32-run-pchum.bat`. - * **(LINUX)** Run `./pesterchum`, preferably via terminal. - * Note that this is made to provide debugging information - so that if - errors come up, they can be reported to me, and I can fix them. - -[python2-32]: https://www.python.org/ftp/python/2.7.12/python-2.7.12.msi -[python2-64]: https://www.python.org/ftp/python/2.7.12/python-2.7.12.amd64.msi -[pyqt4-32]: http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe -[pyqt4-64]: http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x64.exe -[pygame-dl]: http://www.pygame.org/download.shtml -[pchum-zip]: https://github.com/karxi/pesterchum/archive/master.zip - -#### Upgrading -**NOTE: This only applies to those who already have this patched Pesterchum -installed.** -**DO NOT extract this into a folder containing pesterchum.exe, because it WILL -break.** Read up to **First-Time Install** if you're installing this version -for the first time. -Otherwise... - -Just re-download the [Pesterchum zip][pchum-zip] and extract it over your old -installation, replacing everything that was already there. That's all there is -to it! - -#### Having Problems? -I can't offer much help in this regard; if you're getting errors, feel free to -try to contact me, but if you're having trouble with the installers, there's -little I can do. [How to install Python][howtogetpython] might help; failing -that, Google saves lives. - -[howtogetpython]: http://www.howtogeek.com/197947/how-to-install-python-on-windows/ - - - -SMILIES -------- -None of the smilies have changed or been added, yet; this list is kept for -posterity and easy reference. - -* `:rancorous:` -* `:apple:` -* `:bathearst:` -* `:cathearst:` -* `:woeful:` -* `:pleasant:` -* `:blueghost:` -* `:slimer:` -* `:candycorn:` -* `:cheer:` -* `:duhjohn:` -* `:datrump:` -* `:facepalm:` -* `:bonk:` -* `:mspa:` -* `:gun:` -* `:cal:` -* `:amazedfirman:` -* `:amazed:` -* `:chummy:` -* `:cool:` -* `:smooth:` -* `:distraughtfirman:` -* `:distraught:` -* `:insolent:` -* `:bemused:` -* `:3:` -* `:mystified:` -* `:pranky:` -* `:tense:` -* `:record:` -* `:squiddle:` -* `:tab:` -* `:beetip:` -* `:flipout:` -* `:befuddled:` -* `:pumpkin:` -* `:trollcool:` -* `:jadecry:` -* `:ecstatic:` -* `:relaxed:` -* `:discontent:` -* `:devious:` -* `:sleek:` -* `:detestful:` -* `:mirthful:` -* `:manipulative:` -* `:vigorous:` -* `:perky:` -* `:acceptant:` -* `:olliesouty:` -* `:billiards:` -* `:billiardslarge:` -* `:whatdidyoudo:` - - - -[modeline]: vim:set autoindent ts=4 sts=4 sw=4 tw=79 expandtab: diff --git a/README-pesterchum.mkdn b/README-pesterchum.mkdn deleted file mode 100644 index 6b7c6c4..0000000 --- a/README-pesterchum.mkdn +++ /dev/null @@ -1,840 +0,0 @@ -Welcome to Pesterchum 3.41! -============================= - -WHAT'S NEW? ------------ -* Check out the CHANGELOG file to see what's changed! - -What do I do now? ------------------ - -Most questions can be answered by visiting the forums! Go to HELP->HELP -and you'll be transported to the proper thread! - -Here's some tips to help you get started: ------------------------------------------ - -- Some themes can be confusing if you haven't used the program -already! Some hints: - * Trollian: Moods are set by clicking the timelines, and you -can add chums by clicking "Chumproll." Moods correspond to the troll -that would most likely exhibit them. You can go offline by hitting the -"Timelines" menu bar. - - * Gold: Add chums by hitting the two chumpeoples in the upper left -corner. Go offline by clicking the "CHUMHANDLE:" label. - - * Enamel: Add chums by hitting the "CHUMROLL" label. Go offline by -clicking the upper left hand corner. - -- Right-click is your friend! There are useful right click -options on the chumroll, by clicking the chumhandle in a conversation, -online userlist, or the list of memo browsers. - -Cool features: --------------- - -- Profile switching. Instantly switch profiles, loading your color and -quirks with it. -- Theme switching and creation. So far this comes with a few official -themes! But you can also make your own: just make a new directory in -the themes folder with the proper images and style.js file. The -style.js file will be documented soon, but feel free to poke at it. -- Memos. Memos that are a lot more like the ones in the comic and -allow you to appear at multiple times in one chat. -- Quirks: Prefix, suffix, simple replace, regexp replace (like in -2.5), random replacement, and an auto-mispeller :P -- Chum groups. Organize your chums into collapsible groups for easy -management. -- Block/user list -- Add/block chums directly from a conversation, the userlist, or memo -userlist. -- Timestamps saved in logs and shown in conversations if wanted. -- Logging. Logs are output in bbcode (for easy forum posting), html, -and plain text. -- Logviewer for easy log reading inside Pesterchum -- Idling. You can set yourself idle manually, and the computer will -set it for you after a configurable amount of time. -- Improved /me. Any letters immediately following /me will be -processed correctly. e.g. /me'd rather be fishing -> `-- ghostDunk'd -[GD'D] rather be fishing --` -- Hyperlinks! Now if someone types http://whatever it will turn into a -link you can just click and follow. No more copy/paste. -- Memo links. Link your friends to your memos. -- Smilies. We've added about 30-40 smilies from the forums. There is a -list later on in this readme. -- Submit quotes directly to the Pesterchum QDB! - -FA% ---- -__Q:__ Norton says it has a virus and then deletes it! -__A:__ Read this helpful Norton FAQ: - -Alright, here's a guide to by-passing Norton: - -* First, to download Pesterchum: - 1. Make sure you're on a Moderator account. Moreso for the Norton steps than these ones. - 2. Download the .zip file, not the .exe file. - 3. Unzip the .zip file onto memory. Pesterchum should now be installed. - -* Now, to by-pass Norton: - 1. Make sure you're still on a moderator account. - 2. Open up Norton. - 3. Click on 'Settings' up in the upperright hand corner. - 4. Click on 'Anitivirus', off to the upper left. It has a small image of a needle or something similar off to it's side. - 5. There's a word that reads 'SONAR protection' halfway to the bottomleft. Off to it's right, there's a bar that's half green. Click on the bar. - 6. It will warn you about turning off SONAR. Have it set to turn back on when the system restarts. - 7. If done properly, the background for the main page of Norton(what you saw on steps 2-3) has turned an apocaliptic red. Feel free to close Norton now. Keep in mind to stay off suspicious online sites now. - 8. Open up Pesterchum, and let the chummy convos begin. - -* When finished: - 1. Log off of Pesterchum. LOG OFF, NOT CLOSE IT. - 2. Then, you can either shut off your comp, and Norton will re-enable SONAR, or you can repeat steps 1-5, except turning the red bar green. If done right, Norton will be it's happy color again. - 3, Keep in mind that you must repeat all of this(other than the download) every time you want to get on Pesterchum. - -* Hope this is helpful! - -(This guide brought to you by the slightly combined efforts of empireomega and Xanaomin) - ------------------------------------------------------------------------------------- - -__Q:__ I can't connect because my school/university/network/stolen wifi is blocking my connection! OR I can't seem to connect to the server at all and I'm not running any firewalls! -__A:__ Edit your pesterchum.js file. Open it up in notepad or something, and then edit the beginning so it looks like this: - -``` -{"port": "1413", .... -``` - -where the .... is the rest of the gobbledygook there. - ------------------------------------------------------------------------------------- - -__Q:__ The mood buttons on Pesterchum 6.0 don't match up to what it sets your mood to! What gives? -__A:__ The mood names are just there to look canon. It is intentional. - ------------------------------------------------------------------------------------- - -__Q:__ I'm appearing as offline to 2.5 users/other users appear the wrong -mood? What's happeninggggg -__A:__ The 2.5 people decided to change the mood protocol. When I made -this program, I decided to go with Tinychat's original protocol (and -extend it). So some moods will appear wrong between 2.5 -users. (\*COUGH\*tell them to switch to 3.14\*COUGH\*) - ------------------------------------------------------------------------------------- - -__Q:__ Pesterchum 2.5 users don't get my /me messages correctly! -__A:__ That's because they implemented the /me command differently. - ------------------------------------------------------------------------------------- - -__Q:__ Can we resize the main window? -__A:__ No. This is done so we can offer more flexible UI creation. It's a -lot easier to make themes that look canon this way. - ------------------------------------------------------------------------------------- - -__Q:__ Can we have different chum rolls for different users? -__A:__ No. Instead what we now have crum groups to organize people. - ------------------------------------------------------------------------------------- - -__Q:__ Can we delete profiles? -__A:__ Yes. Go to the profile switcher, choose a profile and press DELETE. - ------------------------------------------------------------------------------------- - -__Q:__ You should make it so you can ban specific time frames in memos. -__A:__ This was too complicated to implement, and I don't have the UI -quite figured out. This will probably go in a future update. - - -DOCUMENTATION -------------- - -STARTING --------- - -If this is your first time running Pesterchum 3.14, you need to create -a new profile. Just type in your chum handle in the box and click the -color swatch to pick your color. Check the "default" checkbox to make -this your default profile. - -BASIC PESTERING ---------------- - -To begin pestering, first click the "ADD CHUM" button and type in -their pester handle. The handle must be all lower case except for one -capital letter. Once you've added that person, they will appear on -your chumroll. You can double click to begin pestering them, or -right-click to bring up a menu where you can pester them, block them, -or remove them from your chumroll. (Or you can select them and hit -"enter" OR hit the "PESTER" button.) - -Once you begin pestering somebody (or they begin pestering you), it -will bring up the conversation window. Here you can type to your -chum. Also remember that if you right-click on the area just above the -Pesterlog, it will bring up a list of options: Quirks Off will turn -your quirks off, Add Chum will add this chum to your list, and Block -will block them. (Those last two options are useful if you are being -pestered by someone you don't have on your list yet!) - -While pestering your chum, here are some useful features: - -* Type /me to create a system message. "/me facepalms." will generate: - - ``` - -- ghostDunk [GD] facepalms. -- - ``` - - You can also append 's after /me like so: "/me's computer exploded." - - ``` - -- ghostDunk's [GD'S] computer exploded. -- - ``` - - In fact, any characters you type after a /me before the space will - be added: "/meing is the Ghost Nation's official pastime." - - ``` - -- ghostDunking [GDING] is the Ghost Nation's official pastime. -- - ``` - -* Color tags! If you feel the need to talk about The Green Sun or add - some appleberry blast to your conversation, just use color - tags. These work like in TC 1.5: `colored text
`. But in - PC 3.14, you can type your color in a lot of different ways: - - - You can use the familiar r,g,b method: - `The Green Sun` - - You can use HTML tags: - `DURR I'M KARKAT AND I'M A HUGE IDIOT` - - You can even use [plain color names](http://en.wikipedia.org/wiki/Web_colors): - `D4V3 TH1S 1S SO D3C4D3NT` - - You don't even have to add the `` if you are lazy. Just use a - new color tag whenever you want to change colors and PC 3.14 will - add the extra tags for you. - -* URLs (anything with `http://` or `www.` in front of it) will automatically be - detected and made into a link you can CLICK. - -* You can also link people to memos by typing "#" and the name of the - menu like so: #R41NBOW_RUMPUS_P4RTYTOWN - Clicking the link will open up the memo select menu. - -* Smilies! There are a list of smilies at the end of this document; - they are based on the MSPA Forum smilies. - -* Don't worry about your quirks screwing up any of the above: PC will - apply your quirks AFTER it figures out color codes, links, smilies, etc. - -* Pressing the up arrow will cycle through a history of your comments, - so if you want to retype something, you can pull it up. - -* You can submit directly to the Pesterchum Quote Database! If you - have a particualarly awesome conversation, you can submit it to the - database by simply highlighting the good part of the conversation, - right clicking it and choosing "Submit to Pesterchum QDB!" - - -MEMOS ------ - -One of the most interesting features to make was the memos, and make -them as close to the comic as I could without actually inventing time -travel. So here is the TIME TUTORIAL: - -* __Joining:__ When you go CLIENT->MEMOS, you'll see a list of memos pop up --- those are memos people already have open. To join one, just -highlight one of them. If you want to make a new memo, just type it in -the input. If you'd like to make it secret, so that it doesn't appear -in the list, check "HIDDEN CHANNEL". Then, choose what timeframe you -want to appear to be in. So if you wanted to be in the future, you -could move the slider to the right. You can also enter the time -manually. Then hit JOIN. - -* __Explaining time:__ Time in memos, unlike Homestuck, will not be relative -to your position. That is, if you choose 4:13 in the future, you will -not see someone who has set their time as "current" (or "0") in the -past: you will see them as "current" and yourself as "future." This is -because we do not have time travel! Memo time setting is basically an -RP mechanic: you are pretending to be from the future! It will also -help keep everyone straight: everyone will see the same thing! - -* __The time slider:__ The slider shows your current position in the time -stream. If you want to change your time frame, simply move the slider -(or type a time in) and hit GO. This will open a new time frame, and -the next time you type a message, the memo will show that you've -responded to it in that time frame. You can now switch between your -time frames simply by clicking the arrows in the right hand -corner. (THIS COMES IN HANDY IF YOU WANT TO ARGUE WITH YOURSELF.) You -can have any number of open time frames, and the program will number -them in the order in which you open them (like in the comic). You can -have one of your time frames cease responding to the memo by hitting -"CLOSE." If you open that time frame again, the program will remember -the number it originally gave it. If you want to be mysteeeeeeeerious, -you can type in "?" and you will appear as ???. - -* __The memo viewer list:__ To the right is a list of people currently -browsing the memo. A shade icon next to their name means they are the -"operator" of the memo: meaning they can kick ("ban") people from the -memo and make other people operators as well. A "ban" is not permanent -(like in the comic), and the program will ask if you want to reconnect -to the memo. You kick and op people by right clicking their name in -the window. You can also add them to your chumroll! - -* __Inviting people to your memo:__ You can link to a memo by simply typing -"#nameofmemo" in any conversation or memo window. So you can say: - - ``` - CG: NOW YOU, ME, AND EGBERT NEED TO HAVE A CHAT. - CG: CLICK IT. - CG: #FRUITYRUMPUSASSHOLEFACTORY - ``` - - and it will appear as a link that you can click, which will open the - memo chooser window. - -CLIENT MENU ------------ - -### OPTIONS: ### - -* __Chum List__ - * __Hide Offline Chums:__ Turning this option on will hide all offline chums - off your chumroll. - - * __Show Empty Groups:__ Turning this option on will show empty groups. - - * __Show Number of Online Chums:__ Show number of online chums in each group. - - * __Sort Chums:__ How would you like your chums sorted? - -* __Conversations__ - * __Time Stamps:__ Turning this on will show timestamps in your chats. - - * __12/24 hour:__ Formatting for timestamps. Whether you want them in 12 or - 24 hour time. - - * __Show Seconds:__ Turning this on will show the seconds in your timestamps. - - * __Show OP and Voice Messages in Memos:__ Whether or not you would like - to see messages when people gain/lose OP or Voice. - - * __Use animated smilies:__ To animate or not to animate. - -* __Interface__ - * __Tabbed Conversations:__ Turns tabbed conversations on and off. Don't - worry if you do this in the middle of a conversation, PC will save - them for you. - - * __Minimize:__ What do you want the minimize button to do? - - * __Close:__ What do you want the close button to do? - -* __Sound__ - * __Sounds On:__ Uncheck to shut it the fuck up. - - * __Pester Sounds:__ Uncheck to only turn off Pester sounds. - - * __Memo Sounds:__ Uncheck to only turn off Memo sounds. - - * __Memo Mentions:__ Check to have a separate noise when your initials - get mentioned in a memo. - -* __Logging__ - * __Log all Pesters:__ Log one-on-one chats. - - * __Log all Memos:__ Log everything said in memos. - - * __Log Time Stamps for Pesters__ - - * __Log Time Stamps for Memos__ - -* __Idle/Updates__ - * __Minutes before Idle:__ How long before you should be considered idle. - - * __Check for Pesterchum Updates:__ How often to check for updates - to Pesterchum. - - * __Check for MSPA Updates:__ Check the MSPA site for updates to comics. - -* __Theme__ - * __Pick a Theme__ - -### MEMOS: ### - -Opens the Memo list as above. - -### USERLIST: ### - -Shows a list of all the users that are currently logged onto -Pesterchum. Right-click their names and select "ADD CHUM" to add them -to your chum roll! - -### IDLE: ### - -Make yourself an idle chum. You will appear as idle until you -uncheck this box, or if you *actually* go idle (stop using the -computer) for 10 minutes and then come back. - -### IMPORT: ### - -Imports your old Pesterchum 2.0, 2.5 and Tinychum chum -rolls. This will also import your old quirks from Pesterchum 2.5. - -### RECONNECT: ### - -Forces PC to reconnect to the server. - -### EXIT: ### - -noooooooooooooooooooooooo - - -PROFILE MENU ------------- - -### QUIRKS: ### - -Opens the quirks menu. More on that below! - -### TROLLSLUM: ### - -Opens up the window where you can view people you've -blocked. You can add and remove people to the list from here as well. - -### COLOR: #### - -Change your text color here! - -### SWITCH: ### - -Switch your profile! You can have any number of profiles, and -PC will save your color, quirks, and theme for that profile. Chumrolls -and block lists are the same for all profiles. Feel free to have -multiple instances of PC running on two or more handles! - - -HELP MENU ---------- - -### HELP: ### - -Get taken to a handy dandy tutorial for Pesterchum! - -### CALSPRITE: ### - -Open a chat with calSprite (learn more about calSprite below). - -### NICKSERV: ### - -Open a chat with NickServ. If you don't know what NickServ is, you don't need to. - -### ABOUT: ### - -See which version of Pesterchum you have. Learn about all the awesome people -that helped bring Pesterchum 3.14 to you! - -### REPORT BUG: ### - -Report any bugs you come across so we can fix them and make Pesterchum -even better! - - -CALSPRITE ---------- - -calSprite is the bot that helps moderate canon handle usage! Simply pester -calSprite with the world "HELP" (turn your quirks off!) and you -will get instructions on how to use calSprite! - - -QUIRKS ------- - -There are six kinds of quirks! I'll teach you how to use them all! -(In this section, I will use quotes ("") around things so it's clearer -to see exactly what to type! Don't include these quotes when using -these examples! - -Also, note that your quirks will not work until you save them by -hitting "OK" on the Quirk window. - -* __Prefix/Suffix:__ - This will put text before or after everything you - say. So for example, we can use prefixes to emulate part of Nepeta or - Equius' quirks: - - ``` - PREFIX: ":33 < " - You type: "*ac twitches her friendly whiskers at ct*" - Result: - AC: :33 < *ac twitches her friendly whiskers at ct* - ``` - - ``` - PREFIX: "D --> " - You type: "Hi" - Result: - CT: D --> Hi - ``` - - Suffixes work the same way, but at the end of the message: - - ``` - SUFFIX: "!!!" - You type: hey there - Result: - GD: hey there!!! - ``` - - Remember that it doesn't automatically add a space! You'll need to add - it in (see CT and AC examples again!) - -* __Simple Replace:__ -This will simply take a set of characters and replace them with other -characters. - * Let's add a quirk to our Nepeta: - - ``` - Replace: "ee" With: "33" - You type: "*ac saunters from her dark cave a little bit sleepy from - the recent kill*" - Result: - AC: :33 < *ac saunters from her dark cave a little bit sl33py from the - recent kill* - ``` - - * Let's add two to Equius: - - ``` - Replace: "loo" With: "100" - Replace: "x" With "%" - You type: "look" - Result: - CT: D --> 100k - ``` - - ``` - You type: "What are you expecting to accomplish with this" - Result: - CT: D --> What are you e%pecting to accomplish with this - ``` - - * Aradia: - - ``` - Replace: "o" With: "0" - You type: "and the reward would be within our reach" - Result: - AA: and the reward w0uld be within 0ur reach - ``` - - Notice that it is CASE SENSITIVE. So in the above case, if you typed - "ABSCOND", it would not replace the "O". - - * Sollux: - - ``` - Replace: "i" With: "ii" - Replace: "s" With: "2" - ``` - - * Eridan: - - ``` - Replace: "v" With: "vv" - Replace: "w" With: "ww" - ``` - - * Feferi: - - ``` - Replace: "h" with: ")(" - Replace: "H" with: ")(" - Replace: "E" with: "-E" - ``` - -* __Regexp Replace:__ -This is a more complex kind of replacement. [Regexp](http://en.wikipedia.org/wiki/Regexp) -stands for "regular expression", a kind of programming language (yes, it is a language) -used to find and replace text. PC 3.14 also includes a few functions (`upper()`, -`lower()`, `scramble()`). If you want to learn it on your own, -I suggest you start with the [Python tutorial](http://docs.python.org/howto/regex.html) -since PC 3.14 uses Python's regexps. Check out V2.5's tutorial too, as that is a pretty -good start as well. - - * Let's start with Karkat. Regexps are just like your every day find and - replace: they search for a string that matches what you want to - replace, and replaces it with... the replacement. - - ``` - Regexp: "(.)" Replace with: "upper(\1)" - ``` - - Three concepts here. Let's look at the regexp. "(.)" has two things - going on. The first is that ".". In regexp speak, "." is the wildcard: - it will match *any* character -- and just one. - - The parentheses tell the regexp to *save* what's inside them so you - can put it back when you replace. That's what the "\1" is for -- it - means, "put the match inside parentheses #1 here". You can have any - number of parentheses. - - * __"upper()"__ is a function special to PC 3.14 -- it will uppercase - anything inside the parentheses. So in this case, upper will uppercase - "\1" -- which, as you recall is what we found inside the - parentheses. Which was *every* character. So to sum up, it replaces - every character with an uppercase version of that character. WHICH - MAKES YOU TALK LIKE THIS. - - * Let's look at Terezi next. - - ``` - Regexp: "[aA]" Replace with: "4" - Regexp: "[iI]" Replace with: "1" - Regexp: "[eE]" Replace with: "3" - Regexp: "(.)" Replace with: "upper(\1)" - ``` - - We already know what the last line does. But what's up with those - brackets? What's their deal? Basically, in regular expressions, - brackets indicate a list of matching characters. So, basically any - single character within the brackets will be matched. In this case, - either "a" or "A" will be matched and replaced with "4," and likewise, - "i" and "I" will be replaced with "1", and "e" and "E" will be - replaced with "3." - - Just like there is an `upper()` function, there is also a `lower()` - function. It acts just like `upper()` but instead makes everything - inside the parentheses lowercase. This allows you to do things like: - - ``` - Regexp: "(.)" Replace with: "lower(\1)" - You type: "I AM YELLING" - Result: - GD: i am yelling - ``` - - Along with the upper and lower functions is a `scramble()` function. - The purpose of this function is to randomly scramble anything inside - the parentheses. - - ``` - Regexp: "(\w)(\w*)(\w)" Replace with: "\1scramble(\2)\3" - You type: "hello there" - Result: - GD: hlelo trhee - ``` - - This particular regular expression scrambles all of the letters in - the middle of a word. Notice that the "h" and "o" at the beginning - and end of hello remain in place while the other letters are scrambled. - - You should also know that "^" is a special character in brackets. If - placed immediately after the opening bracket (like "[^"), then the - brackets instead match every character *except* the ones in the - brackets. So, for example, if you wanted to have a quirk where you - capitalized all your letters *except* o, you'd do this: - - ``` - Regexp: "([^o])" Replace with: "upper(\1)" - You type: "hello there" - Result: - GD: HELLo THERE - ``` - - You can also specify a *range* of characters inside the brackets, by - using the "-" character. [a-z] will match any lowercase letter. You - can combine them, too: [a-z0-9] will match any digit and lowercase letter. - - There are also different shortcuts for character types: - - ``` - \d matches any digit; same as [0-9] - \D matches any non-digit; same as [^0-9] - \s matches any spaces - \S matches any non-space - \w matches any alphanumeric character; same as [a-zA-Z0-9_] - \W matches any non-alphanumeric character; same as [^a-zA-Z0-9_] - - Note \w and \W also match extended Latin or Unicode alphanumerics. - ``` - - You can include this inside brackets, too. - - There's also a special character, \\b. What \\b does is make sure that - you are at the beginning or end of a word. - * So with that knowledge, let's try Kanaya: - - ``` - Regexp: \b(\w) Replace with: upper(\1) - You type: "i suggest you come to terms with it" - Result: - GA: I Suggest You Come To Terms With It - ``` - - Another feature of regular expressions is the ability to match - *repeated* characters. There are three repeat characters: the "\*", the - "+", "?", and "{m,n}". They work by playing them after the character, - or character type you want to match. (So, you could say "\s+" or ".*") - - The "\*" character matches ZERO or more of that character. So, for - example, "f\*" would match "", "f" and "ff" -- and any other character! - That's right, every character counts as matching it zero times. Yeah, - it's weird. I suggest you use... - - The "+" character matches ONE or more of that character. So, if we - wanted to have a character that wanted to elongate their s's so that - they used four 's's every time, like sssso, but didn't want to have - eight s's when using words with double s's, like pass, we'd do this: - - ``` - Regexp: "s+" Replace with: "ssss" - You type: "you shall not pass" - Result: - UU: you sssshall not passss - ``` - - As for the other two, I can't really think of any useful quirks to be - made with them. But to let you know, "?" matches either 0 or 1 of that - character, so "trolls?" would match "troll" and "trolls". "{m,n}" - matches between m and n characters. (If you leave out 'n', any number - of characters more than m will be matched: "s{3,}" will match 3 or more 's'.) - So "s{2,4}" will match "ss", "sss", and "ssss" and that's it. - - Also, "?" is equivalent to "{0,1}", "*" is equivalent to "{0,}", and - "+" is equivalent to "{1,}". - - Now with repeating expressions, we can do something like make EVERY - other WORD capitalized: - - ``` - Regexp: "(\w+) (\w+)" Replace with: "upper(\1) \2" - You type: "this is pretty annoying i bet" - Result: - GD: THIS is PRETTY annoying I bet - ``` - - The \1 represents the first word -- which has been matched because the - word is alphanumeric characters, repeated once or more -- and \2 - represents the second word. - - Another operator to use is the "|", which will match more than one set - of characters. For example, "black|red" will match "black" or - "red". If you want to match something in the middle of words, you have - to use parentheses: "(black|red) romance" will match "black romance" - and "red romance". - - Finally, there are the "^" and "$" characters. Yes, we already did the - "^" character, but this is OUTSIDE of brackets, not INSIDE. "^" - matches the beginning of a message, and "$" matches the end of it. You - can use this to make more sophisticated prefix and suffix - behaviors. For example, if we have a quirk that adds "..." to the end - of all our messages, we can set it up so it doesn't do that if we put - punctuation [?!.] at the end. So: - - ``` - Regexp: "([^?!.])$" Replace with: "\1..." - ``` - - This will match the end of any message as long as it doesn't have - "?", "!", or "." at the end. Then it will replace it with whatever the - last character of the sentence was (remember we're replacing it, so we - have to put it back!) and add "..." at the end. - - Careful with the beginning and ending replaces -- if you use more than - one, you may not get what you expect because they will ALL be applied, - one after the other! This is a bug in my opinion, that I plan to fix! - -* __Random replace:__ - Just like the regexp replace, except that instead of just one thing to - replace it with, you give it a list. PC will then choose from that - list randomly. So let's say I want to randomly end my sentences with - either "bro" or "dog": - - ``` - Regexp: "$" Replace with: "bro" and "dog" - ``` - - * You can also imitate Araida's random "ribbits" in between words: - - ``` - Regexp: "\s" Replace with: " ribbit ", " ", " ", " ", " ", " ", etc.... - ``` - - where " " is just a blank space added a bunch of times. (You can see - how many blank spaces you've added by clicking on the list.) You have - to add the spaces because each entry has the same chance of being - selected. (Yes, I know this could be improved.) If you add " ribbit " - and 9 spaces, " ribbit " will have a 1/10 chance of being picked. - - Also note that if you add more than one prefix or more than one - suffix, it will pick randomly from them instead of adding them both! - -* __Mispeller__: -Be careful with thsi one. The mispeller will randomly mispell x% of -the words you type -- where x is the percentage you set the slider -to. I have attempted to mimic SBaHJ mispelling style but whoof knows -what will happen oh god ive created a mosnter - - -SMILIES -------- -Here's a list of smilies: - -* `:rancorous:` -* `:apple:` -* `:bathearst:` -* `:cathearst:` -* `:woeful:` -* `:pleasant:` -* `:blueghost:` -* `:slimer:` -* `:candycorn:` -* `:cheer:` -* `:duhjohn:` -* `:datrump:` -* `:facepalm:` -* `:bonk:` -* `:mspa:` -* `:gun:` -* `:cal:` -* `:amazedfirman:` -* `:amazed:` -* `:chummy:` -* `:cool:` -* `:smooth:` -* `:distraughtfirman:` -* `:distraught:` -* `:insolent:` -* `:bemused:` -* `:3:` -* `:mystified:` -* `:pranky:` -* `:tense:` -* `:record:` -* `:squiddle:` -* `:tab:` -* `:beetip:` -* `:flipout:` -* `:befuddled:` -* `:pumpkin:` -* `:trollcool:` -* `:jadecry:` -* `:ecstatic:` -* `:relaxed:` -* `:discontent:` -* `:devious:` -* `:sleek:` -* `:detestful:` -* `:mirthful:` -* `:manipulative:` -* `:vigorous:` -* `:perky:` -* `:acceptant:` -* `:olliesouty:` -* `:billiards:` -* `:billiardslarge:` -* `:whatdidyoudo:` diff --git a/README.md b/README.md deleted file mode 100644 index c700b9b..0000000 --- a/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Pesterchum Alternate Servers -Pesterchum with added functionality to connect to alternative servers. (And some other stuff.) - -Normal pesterchum documentation is in "README-pesterchum.mkdn" and the one for Karxi's fork is README-karxi.mkdn. - -## Servers -If you'd like to connect to a different server than the default "pesterchum.xyz", put the server you'd like to connect to in the server.json file. - -## Tips for building -- For windows use "setup.py". PyQt4 binaries for windows can be installed from it's sourceforce page if you don't want to go through the hell that's compiling it manually. -- On mac you can install most of the dependencies via macports and build with "python setup-py2app.py py2app". diff --git a/TODO.mkdn b/TODO.mkdn deleted file mode 100644 index eb1dfc7..0000000 --- a/TODO.mkdn +++ /dev/null @@ -1,358 +0,0 @@ -# Todo - -## Git -* Set up issue tracking for this fork, if possible (and move the TODO list) - -## Features -* Log viewer needs to have BBCode/HTML/Text copy modes -* Turn @ and # links on/off? -* Show true bans? COMPRESS QUIT MESSAGES ON BAN -* Colour saving boxes things? -* Whowas for last seen online? -* Tab completion of two letter names -* Auto download/install updates via Windows installer -* Make toast notifications only on certain chums -* Local alisas for chums -* Don't make new windows be all in your face and shit -* Hide offline friends per group - - -* Add support for displaying more verbose information (e.g. Cease messages which - tell you more than the abbreviation of who left) -* Make Pesterchum recognize conventional /mes so they aren't invisible -* Make @XY and @xxxYyy formats ping their targets -* Allow matches like @?XY and @FXY or @PXY3 - make them only match the target - currently set to that. -* Make @ notation not match @u@; and similar (make invalid nick chars break - matches) -* Allow use of @ and # links to switch between logs in log viewer (start with - the closest time to the line of the log that's linking) -* Improve log viewer in general (unbind instances from specific users/memos) -* Fix hyperlink escaping (Qt seems to do this automatically - need a workaround) -* Show bans if +h or higher (+h, +o, +a, +q) -* Auto-invite (for people on the friends list?) -* Right click on names for inviting, ACTUALLY banning, PMing, ... See also: - Things proper IRC clients can do. (Set basic mode stuff up first, get the - infrastructure in place.) - -* Add more comprehensive status support - IDLE, DND, INVISIBLE for now - or at - least add similar functionality. -* Improve Pesterchum's tracking of disconnections (check memos for quits...) -* SEPARATE FUNCTIONALITY from CONNECTED STATE!! This is a huge problem! Being - shunted off our nick closes windows and breaks things! Just D/C and - reconnect? - * It'd probably be best to give an option to either CHANGE NICKS or - DISCONNECT upon nick collision...? But, then how would we GHOST? - * Auto-disconnect if collision before joining channels, make it - possible to disconnect (but not send messages, obviously) - without losing everything - * Maybe GHOSTing should use auto-identify to ensure- no, that doesn't - work, because we can't ident into a specified nick without being ON - it. Need GD's help to fix.... - -* Make it possible to test quirk things and such without connecting? This'd be - hard to separate out, but useful. - * Make a quirk 'bin' that exists independent of profiles, and can be - copied to/from at will. - * Allow us to set quirks that apply to all profiles! For things like - replacement quirks. - -* Right-click Time entry field to see those used? (Replace left/right buttons?) - * Save commonly-used times on a per-handle basis! -* Make the memo list highlight/recolor the names of channels you're in - (including secret ones) -* Add an option to Cycle (for log separation) - -* Add a separate 'Tweaks' section in Options -* Fix graphical issues with dark themes vs. light themes (Qt/text too - light/etc.) - -### Services -* Use web connection to send offline messages in email-like fashion - (Idea: ghostDunk) -* Better NickServ registering -* Implement **MemoServ** support -* Tell user when NickServ handles are going to expire -* Tell user when old handles have D/C'd? Offer autoghost support?! - -### GUI -* Refactor code to make way for QShortcut usage. (Unify shortcut processing?) - * Enable/Disable toggle (Firefox style option sheet-esque? Seems okay.) - * Ctrl+W closes tab - * Ctrl+Shift+PGUP/PGDN moves tab - * Option to disable Ctrl+Tab's jump to newest - * Ctrl+Shift+V "Mass Paste" option (parse lines in sequence)? -* Make mouseovers (refocusing) reset idle timer (disableable) -* Set up EVENT FILTERS in windows to redirect events to the right places - * Make the context key (if used in the text area) append the menu options - from the right-click menu -* Make system messages use timestamps like everything else -* Offer option for timestamps in memos -* Make a status window/popup to contain logs of information like invites - -### "Security" -**Note: The idea of security on this platform is pretty much laughable. Most of -these changes are simply bandages being placed over fundamentally flawed -design.** - -If you want Pesterchum to be more secure, either get ghostDunk to make changes -to the server and its administration policies, or get everyone to switch to this -version of the client. There aren't really any other options. - -* Flood protection (don't send because of the same target too many times in a - row) - * Just requires a timer + lastmessage date check. -* Lock exploitable functionality to those on your friends list (optional) - * Canon handles are excluded from this concern, but subject to flood - controls regardless. - * A measure of politeness is reasonable here - checking if a friend is on - as a different handle should be okay, once IRC access is revamped. - * Don't send MOOD answers to those not friended - * Ignore pesters from those not on your friends list (optional) - * Ignore pesters from those not sharing a memo? (optional) -* Make BLOCKED list persistent, if it isn't already - * Offer option to block hosts, not just handles... - * Explain to the user that this option is very dangerous. - -### Advanced -* Offer option for 'new' syntax adjustments - * Replace: "???, ???, ??? ceased responding to memo." for parts. - * "XY ({handle}) ({times}) ceased responding to memo." - * If +h or above: Include host as well as handle. - * Replace: "??? ceased responding to memo." for nickchanges. - * "XY ({handle} {host?}) left memo; AB ({handle} joined memo." - * Can violate the norms somewhat, these aren't theme-controlled. - They're basically for power users/admins. -* Offer GUI changes - * Make tabs "{name} ({# of unread msgs})" if unread - * Make themes able to define colors that are too dark to read for an - individual window - * Set up code for 'nudging' color codes into readable territory; presumably - via an adjustable setting. (This CANNOT affect logs - just the log - reader.) -* Come up with a solution for duplicate times/handle abbreviations - * Maybe make mouseover for the handles display the full handle? - -* Option to disable backwards compatibility: - * For those that are *really* sure that this build is the build for - them. - * Should enable extra features, including ctag compression. - * Allow manual compression changes via memo right-click menu for - 'advanced' (per the setting) users - -## Todo/Done -**Everything in this section has already been completed.** - -### GUI -* Toggle individual tab flash / alert sounds (from the same right-click memo - that lets us toggle OOC) -* Make CTRL+PGUP/PGDN switch memo/pester tabs -* Make Ctrl+J/K usable for tab changing -* Make right-clicking on a tab open up the right-click menu one would get on - right-clicking the title (frame??) -* Right-click in userlist offers option to Pester -* Make certain dialogues start on the safer of the two options - * Make the Reconnect dialog start on Reconnect - * Make the Rejoin dialog start on Rejoin - * Make the Invite dialog start on Decline - -### Usability -* Fix parser text-loss bug that plagues everyone (especially Chumdroid users) -* Make /me messages that cut continue into more /me messages -* Make sound work on Windows through QSound (disables volume control) -* Color tags are now posted as their shorter hexadecimal forms, if applicable - (255,255,255 -> #FFFFFF, for example) -* Separate auto-idle and checkbox idle so they don't share a state (and make - the first send set the timer for additional idle responses) -* Stop us from sending IDLE messages to NickServ -* Fix NickServ auto-login things -* Make a window that can be used to interface with the script directly - a - simple Python console -* Make the memo name entry box accept a comma-separated list -* Make console users able to check widget theme/style information via mouseover - and key combo (for people making themes or debugging) - * This is presently Ctrl+Alt+w, after opening the console (Ctrl+~). -* LET PEOPLE TURN OFF HONKING - people already rename the soundfile and such to - do this manually (append "honk":false to the end of pesterchum.js ; that kills it.) - -### Backend -* Perpetual code cleanup, refactoring, simplification and general improvements -* Syntax changes/updates and the like - -## Code -**Improvements and changes pertaining to Pesterchum's internals.** - -### General -* Implement new Lexer for the sake of everyone's sanity - * This is half-done - rendering still uses the old lexer -* Redo `PESTERCHUM:` processing/redo whole msg received processing chain -* Redo text processing in general -* Redo quirk processing (use pieces from Textsub if needed) -* Pare down the PesterMemo object so it inherits more things from PesterConvo - *implicitly* -* SOONER OR LATER: Redo internal chum storage, centralize data into widely - accessible manager objects, etc. -* Also: Overhaul settings storage. Bring it more in line with the system Textsub - used (if feeling masochistic), but simpler. -* **Overhaul information storage** - chums, conversations, memos; all should be - handled by a backend and merely RENDERED into Qt objects!! -* Overhaul debugging - * Give an actual (small) window with traceback that can be sent to dev(s) - * Use the console for this? -* Debug generic.py's CaseInsensitiveDict/replace it with mine -* Overhaul messaging so **Chan/Nick/Memo Servs** all use the same code (and - lexer) -* **Separate Pesterchum system handling from window handling.** Dicts should be - stored and maintained via dicts - even a refined version of what I used for - textsub. - * Doing it this way means I can fix the case in/sensitivity issue, too. -* Set up framework for easily logging/accessing channels, users, etc...like - what hexchat has. -* More efficient framework for accessing stored user information - right now, - Pesterchum keeps information on user colors and such on hand *forever*, - meaning that things inevitably get clogged up with handles that are never - really seen, or only seen once, or even just randomly generated. This is - silly and should be changed; I'll probably make a namedtuple for users or - something, and save it all to a separate JSON file or two. - Said JSON file should keep the extra information on hand - or rather, the - 'recent users' JSON file should keep most of the detailed information and be - accessed first, with the larger 'inactive users' file being accessed to - check for unfamiliar handles. - These would have to output the old data to pesterchum.js for backwards - compatibility purposes. -* Finish creating the sound wrapper. Just make it check what the type of sound - needed is upon creation, and instantiate a private class based off of that. - * There is basically no good way to do this without moving to Qt5. I - might try that myself later, but that's a long-term goal. -* Stop from sending TIME notifications when unable - * Until then: Hide resulting "no external messages"/+m messages. -* Stop sending auto-IDLE messages unless the chat has been updated since the - last one. -* Make groups, chums, etc. preferentially load from the main directory, *then* - check logs. - * Compatibility is important, so update both if they exist. (Bluh!) - -### Debugging -* Set up a simple function to display a traceback instead of silently moving on! - * Use the console for this? -* Make small, simplistic windows that allow the viewing of internal variables - pertaining to things like set quirks, users present, etc. - * Also let it display the stylesheet settings of the current window, or - similar. -* Make a console to display debug info without requiring us to run from terminal -* Allow us to specify flags via command line - * Let us specify a separate config (pesterchum.js) file!! -* Make the console support color (not ctags, more stylesheet stuff) (need - parser work for this) - -## Bugs -* weird memo time bug -* Windows doesn't show style sheet sometimes?? Maybe related to themes. -* Issues with connecting? Client not closing connection right? People keep - getting "nick taken" messages -* When using mood sort, scroll position jumps to last selected chum -* Closing a timeclone doesn't actually cease for everyone else -* Kill Zalgo -* Random invisible, tiny links to last link at end of every message -* Chums not appearing on chumroll when initals are the same? (bS) -* Recognize IRC 471, 473, 474 and 475 -* memo links aren't case sensitive - -* Mentions occasionally don't work (e.g. in /me) -* Character times aren't 'forgotten' on Part -* +c is not properly recognized on join, nor does it stop someone from - reenabling their quirk (let ops and above ignore it?) -* Chumlist handles groups pretty badly (no using the same name as a handle, for - example? Needs an errormessage at least) - * The whole chumlist handling system really ought to be refactored into - something sane...the objects should only be there to render -* PESTERCHUM: messages are sent to things like NickServ -* Log folder/file names are not case-sensitive, so they break on non-Windows - systems -* Log viewer needs adjustments and sanity checking for log directories -* Capitalized /me's don't render (should forcibly lowercase them) -* 'pcd10' and similar users don't get proper abbreviations on part (ugh) - -* Volume control doesn't work without pygame -* Sound on Linux doesn't work without pygame -* Update checking code gives false positives (update to use json file from git?) -* Pesterchum doesn't seem to close all of its file handles - it runs out of - handles to use on Linux - * Others have reported memory leak-induced crashes on Windows. These - may or may not be related. -* Pesterchum groups aren't carried over when profiles are copied! -* Malformed Pesterchum profiles cause the program to crash and burn - * What causes these? Exiting in the middle of a write operation? Threading - issues? -* Malformed Python quirks try to open an error dialog and crash if Pesterchum - is opened as a module -* Pesterchum's threading is messy and scary, and should probably be cleaned up - some via the addition of locks -* Pesterchum's file handling is atrocious - inefficient to the extreme. - * There are multiple copies of things that really need only be loaded once - in a lot of different places. - * Memos don't seem to close their file handles properly. (Logs too??) - -## Windows Bugs -* XP SP2: sometimes mouse clicks dont register? must be some kinda crash -* On reconnect and nick change, momentary theme change causes menu items to - stop working -* Random chums won't show up on chumroll -* Popup toast notifications cause main window to raise - -## Mac Bugs -**Due to my lack of access to a Mac, these are unlikely to be fixed.** -* Mac doesn't show tabs right, display gifs, highlighting thing? -* SS: also the background image is broken -* SS: in the one-on-one pester it resizes with the window -* SS: but the memo one doesn't resize -* SS: and the arrows next to the time thing overlap the CLOSE button -* Lex: There seems to be a faint outline around most non-square themes. - - -## Things that won't be done -**Requests that, for one reason or another, will not be fulfilled.** - -### Scrapped Features -**I'll explain why these ones won't happen.** - -> * More complex quirks: by-sound - -* This would require a way to determine what maps to a sound, and - replace it. - I've played with the idea before. It resulted in me needing to look - up things like the [Metaphone Algorithm][metaphone] to figure out - how it might be even remotely possible. The results were NOT a fun - time; if this is ever implemented, it will be much, much later than - just about everything else. -[metaphone]: https://en.wikipedia.org/wiki/Metaphone - -> * Spy mode - -* I feel as though I shouldn't need to tell anyone why this is a bad idea. - Some people already have this capability anyway; I used to be one of them. - There's no real need to implement an inferior version into every single - client on Pesterchum. - -> * "Someone has friended you" notifier -> * Spectation notices (Idea: lexicalNuance) (probly WONTFIX) - -* These are milder invasions of privacy than the above, but they are still - invasions of privacy. - -> * When 'banned' make impossible to connect using timestamp banned under - -* This is a lot of work for something that purely affects immersion - while - also breaking a number of things in the process. Too much work for too - little payoff. - -> * Use web connection to save profiles (Idea: ghostDunk) - -* There is no way to do this now that Pesterchum is basically unsupported; an - external server would be necessary for storage. - As such, you'll just have to settle for copying your profiles and logs when - you change computers. - - - -[modeline]: vim:set autoindent ts=4 sts=4 sw=4 tw=79 expandtab: diff --git a/VERSION.js b/VERSION.js deleted file mode 100644 index 556c1e3..0000000 --- a/VERSION.js +++ /dev/null @@ -1 +0,0 @@ -{"major": 3.41, "minor": 4, "status": "A", "rev": 13, "utype": "dev"} diff --git a/console.py b/console.py deleted file mode 100644 index 6538bd1..0000000 --- a/console.py +++ /dev/null @@ -1,528 +0,0 @@ -# vim: set autoindent ts=4 sts=4 sw=4 textwidth=79 expandtab: -# -*- coding=UTF-8; tab-width: 4 -*- -from __future__ import print_function - -from PyQt4 import QtGui, QtCore -import re, os, traceback, sys -import time, datetime -from os import remove - -import dataobjs, generic, memos, parsetools, ostools -from version import _pcVersion - -try: - from pnc.attrdict import AttrDict -except ImportError: - # Fall back on the old location, just in case - from pnc.dep.attrdict import AttrDict -#~from styling import styler - -_datadir = ostools.getDataDir() - -import logging -logging.basicConfig(level=logging.WARNING) - - - - -class ConsoleWindow(QtGui.QDialog): -#~class ConsoleWindow(styler.PesterBaseWindow): - # A simple console class, cobbled together from the corpse of another. - - stylesheet_path = "main/defaultwindow/style" - # This is a holder for our text inputs. - text = AttrDict() - # I should probably put up constants for 'direction' if this is going to - # get this complicated. TODO! - incoming_prefix = "<<<" - miscinfo_prefix = "==>" - outgoing_prefix = ">>>" - neutral_prefix = "!!!" - waiting_prefix = "..." - - selected_widget = None - show_info_on_select = True - - _CUSTOM_ENV = {} - - def __init__(self, parent): - super(ConsoleWindow, self).__init__(parent) - self.prnt = parent - try: - self.mainwindow = parent.mainwindow - except: - self.mainwindow = parent - theme = self.mainwindow.theme - # This won't initialize the sub-objects, because they don't exist yet. - self.initTheme(theme) - - self.text = AttrDict() - self.text.area = ConsoleText(theme, self) - self.text.input = ConsoleInput(theme, self) - self.text.input.setFocus() - - self.connect(self.text.input, QtCore.SIGNAL('returnPressed()'), - self, QtCore.SLOT('sentMessage()')) - - self.text.history = dataobjs.PesterHistory() - - # For backing these up - self.stdout = self.stderr = None - - layout_0 = QtGui.QVBoxLayout() - layout_0.addWidget(self.text.area) - layout_0.addWidget(self.text.input) - self.setLayout(layout_0) - - def parent(self): - return self.prnt - - def clearNewMessage(self): - pass - - @QtCore.pyqtSlot() - def sentMessage(self): - text = self.text.input.text() - # TODO: Make this deal with unicode text, it'll crash and burn as-is. - text = str(text) - text = text.rstrip() - - self.text.history.add(text) - self.text.input.setText("") - - self.execInConsole(text) - # Scroll down to the bottom so we can see the results. - sb = self.text.area.verticalScrollBar() - sb.setValue(sb.maximum()) - - def addTraceback(self, tb=None): - # We should do the formatting here, but eventually pass it to text.area - # to addMessage whatever output we produced. - # If we're called by addMessage - and we should be - then sys.stdout is - # still being redirected into the console. - # TODO: Just make an object for setting contexts (and thus optionally - # redirecting prints). Use 'with', of course. - # TODO: Make this exclude *our* processing from the traceback stack. - try: - self.addMessage(traceback.format_exc(), direction=0) - except Exception as err: - logging.error("Failed to display error message (???): %s" % err) - - def addMessage(self, msg, direction): - # Redirect to where these things belong. - self.text.area.addMessage(msg, direction=direction) - - def closeEvent(self, event): - # TODO: Set up ESC to close the console...or refer to hiding it as - # closing it. Not sure which is preferable. - parent = self.parent() - parent.console.is_open = False - parent.console.window = None - return super(ConsoleWindow, self).closeEvent(event) - - def hideEvent(self, event): - parent = self.parent() - parent.console.is_open = False - - def initTheme(self, theme): - # Set up our style/window specifics - self.changeTheme(theme) - self.resize(400,600) - - def changeTheme(self, theme): - self.setStyleSheet(theme[self.stylesheet_path]) - self.setWindowTitle("==> Console") - if "area" in self.text and "input" in self.text: - self.text.area.changeTheme(theme) - self.text.input.changeTheme(theme) - - @QtCore.pyqtSlot() - def designateCurrentWidget(self): - # Display and save the current widget! - # TODO: Consider (reversible) highlighting or selection or something - # fancy. It'd help people write styles, wouldn't it? - # ...just remember to use mouseRelease() if you work with hovering. - - # Direction: Misc. Info - direction = 2 - - pos = QtGui.QCursor.pos() - wgt = QtGui.QApplication.widgetAt(pos) - if wgt is None: - # Don't set None, for now. May change this later. - self.addMessage("You need to have your cursor over something " + \ - "in Pesterchum to use that.", - direction=direction) - return - - self.selected_widget = wgt - nchild = len(wgt.children()) - output = [] - output.append("CONSOLE.selected_widget = {0!r}".format(wgt)) - output.append("{0: <4}Parent: {1!r}".format('', wgt.parent())) - output.append("{0: <4}{1:4d} child{2}".format('', - nchild, ("ren" if abs(nchild) != 1 else "") )) - if self.show_info_on_select: - qtss = None - uses_ss = None - try: - qtss = wgt.styleSheet() - except: - pass - else: - if unicode(qtss) == unicode(""): - uses_ss, ss_msg = False, "No" - elif qtss is not None: - uses_ss, ss_msg = True, "Yes" - else: - uses_ss, ss_msg = None, "Invalid" - - ss_par, ss_par_msg = None, "" - if uses_ss is False: - # TODO: Split this into a sub-function or integrate it into - # Styler or *something*. - # The stylesheet was probably defined on a parent higher up. - # Rungs above the start - i = 0 - # qtss is still "" from earlier - while not qtss: - try: - ss_par = wgt.parent() - qtss = ss_par.styleSheet() - except: - # Can't ascend...and we're still in loop, so we don't - # have what we came for. - # Either that, or it's incompatible, which means the - # ones above are anyway. - ss_par = False - break - else: - # Indicate that we got this from a parent - i += 1 - - if not qtss: - # There are no stylesheets here. - if ss_par is False: - # We had parent issues. - # TODO: Specifically indicate invalid parent. - uses_ss, ss_msg = None, "Invalid" - else: - uses_ss, ss_msg = False, "No" - else: - # We got a stylesheet out of this! - uses_ss, ss_msg = True, "Yes" - #~ss_par_msg = "{0: <4}...on parent ↑{1:d}: {2!r}".format('', - ss_par_msg = "{0: <4}...on parent #{1:d}: {2!r}".format('', - i, ss_par) - - msg = [] - msg.append("{0: <4}QtSS?: {1}".format('', ss_msg)) - # A stylesheet analyzer would be wonderful here. Perhaps something - # that tells us how many parent classes define stylesheets? - if uses_ss: - if ss_par_msg: - # We got this stylesheet from a parent object somewhere. - msg.append(ss_par_msg) - msg.append("{0: <4}".format("Stylesheet:")) - for ln in qtss.split('\n'): - msg.append("{0: <8}".format(ln)) - - # Actually add this stuff to the result we're constructing - output.extend(msg) - - output = '\n'.join(output) - self.addMessage(output, direction=direction) - - - # Actual console stuff. - def execInConsole(self, scriptstr, env=None): - # Since that's what imports *us*, this should be okay - # Tab completion could be set up in ConsoleInput, and would be nice - import pesterchum as pchum - - if env is None: - env = pchum._retrieveGlobals() - - # Modify the environment the script will execute in. - # Fetch from the class/instance first. - _CUSTOM_ENV = self._CUSTOM_ENV.copy() - # Modify with some hard-coded environmental additions. - _CUSTOM_ENV.update({ - "CONSOLE": self, - "MAINWIN": self.mainwindow, - "PCONFIG": self.mainwindow.config, - "exit": lambda: self.mainwindow.exitaction.trigger() - }) - # Aliases. - _CUSTOM_ENV.update({ - "quit": _CUSTOM_ENV["exit"] - }) - # Add whatever additions were set in the main pesterchum file. - _CUSTOM_ENV.update(pchum._CONSOLE_ENV) - - _CUSTOM_ENV_USED = [] - cenv = pchum.__dict__ - # Display the input we provided - # We do this here, *before* we do our variable injection, so that it - # doesn't have to be part of the try statement, where it could - # potentially complicate matters/give false positives. - self.addMessage(scriptstr, 1) - for k in _CUSTOM_ENV: - if k not in cenv: - # Inject the variable for ease of use. - cenv[k] = _CUSTOM_ENV[k] - # Record that we injected it. - _CUSTOM_ENV_USED.append(k) - else: - # Don't overwrite anything! - warn = "Console environment item {0!r} already exists in CENV." - warn.format(k) - logging.warning(warn) - # Because all we did was change a linked AttrDict, we should be fine - # here. - try: - # Replace the old writer (for now) - sysout, sys.stdout = sys.stdout, self - try: - code = compile(scriptstr + '\n', "", "single") - # Will using cenv instead of env cause problems?... - result = eval(code, cenv) - except: - # Something went wrong. - self.addTraceback(sys.exc_info()[2]) - else: - # No errors. - if result is not None: - print(repr(result)) - finally: - # Restore system output. - sys.stdout = sysout - finally: - # Try to clean us out of globals - this might be disabled - # later. - for k in _CUSTOM_ENV_USED: - # Remove the key we added. - cenv.pop(k, None) - - def write(self, data): - # Replaces sys.stdout briefly - # We only ever use this for receiving, so it's safe to assume the - # direction is always -1. - if not isinstance(data, list): - data = data.split('\n') - for line in data: - if len(line): - self.addMessage(line, -1) - - -class ConsoleText(QtGui.QTextEdit): - stylesheet_template = """ - QScrollBar:vertical {{ {style[convo/scrollbar/style]} }} - QScrollBar::handle:vertical {{ {style[convo/scrollbar/handle]} }} - QScrollBar::add-line:vertical {{ {style[convo/scrollbar/downarrow]} }} - QScrollBar::sub-line:vertical {{ {style[convo/scrollbar/uparrow]} }} - QScrollBar:up-arrow:vertical {{ {style[convo/scrollbar/uarrowstyle]} }} - QScrollBar:down-arrow:vertical {{ {style[convo/scrollbar/darrowstyle]} }} - """ - stylesheet_path = "convo/textarea/style" - # NOTE: Qt applies stylesheets like switching CSS files. They are NOT - # applied piecemeal. - # TODO: Consider parsing the themes out into stylesheets with pieces that - # we can hand to each widget. - - def __init__(self, theme, parent=None): - super(ConsoleText, self).__init__(parent) - if hasattr(self.window(), 'mainwindow'): - self.mainwindow = self.window().mainwindow - else: - self.mainwindow = self.window() - - self.hasTabs = False - self.initTheme(theme) - self.setReadOnly(True) - self.setMouseTracking(True) - self.textSelected = False - - self.connect(self, QtCore.SIGNAL('copyAvailable(bool)'), - self, QtCore.SLOT('textReady(bool)')) - self.urls = {} - - # Stripped out animation init - it's all cruft to us. - - @QtCore.pyqtSlot(bool) - def textReady(self, ready): - self.textSelected = ready - - def initTheme(self, theme): - # The basic style... - stylesheet = "QTextEdit {{ {style[convo/textarea/style]} }}" - if "convo/scrollbar" in theme: - # TODO: Make all of this into a Styler mixin, so we can just feed - # it a theme whenever we want to change. - # We'd have to define the keys we're affecting, but that shouldn't - # be too hard - it's what dicts are for. - - # Add the rest. - stylesheet += '\n' + self.stylesheet_template - stylesheet = stylesheet.format(style=theme) - self.setStyleSheet(stylesheet) - - def addMessage(self, msg, direction): - # Display a message we've received. - # Direction > 0 == out (sent by us); < 0 == in (sent by script). - if len(msg) == 0: - return - #~color = chum.colorcmd() - #~initials = chum.initials() - parent = self.window() - mwindow = parent.mainwindow - - systemColor = QtGui.QColor(mwindow.theme["convo/systemMsgColor"]) - - if mwindow.config.showTimeStamps(): - if mwindow.config.time12Format(): - timestamp = time.strftime("[%I:%M") - else: - timestamp = time.strftime("[%H:%M") - if mwindow.config.showSeconds(): - timestamp += time.strftime(":%S] ") - else: - timestamp += "] " - else: - timestamp = "" - - # Figure out what prefix to use. - if direction > 1: - # Misc. Info - prefix = parent.miscinfo_prefix - elif direction > 0: - # Outgoing. - prefix = parent.outgoing_prefix - elif direction < 0: - # Incoming. - prefix = parent.incoming_prefix - elif direction == 0: - # We could just 'else' here, but there might be some oddness later. - prefix = parent.neutral_prefix - - # Later, this will have to escape things so we don't parse them, - # likely...hm. - #~result = "{} {} {!r}" - # The input we get is already repr'd...we pass it via print, and thus - # do that there. - result = "{}{} {}\n" - result = result.format(timestamp, prefix, msg) - self.appendPlainText(result) - - # Direction doesn't matter here - it's the console. - self.lastmsg = datetime.datetime.now() - # This needs to finish being rewritten.... - - def appendPlainText(self, text): - """Add plain text to the end of the document, a la insertPlainText.""" - # Save the old cursor - oldcur = self.textCursor() - # Move the cursor to the end of the document for insertion - self.moveCursor(QtGui.QTextCursor.End) - # Insert the text - self.insertPlainText(text) - # Return the cursor to wherever it was prior - self.setTextCursor(oldcur) - - def changeTheme(self, theme): - self.initTheme(theme) - sb = self.verticalScrollBar() - sb.setValue(sb.maximum()) - - def focusInEvent(self, event): - self.window().clearNewMessage() - super(ConsoleText, self).focusInEvent(event) - - def keyPressEvent(self, event): - # NOTE: This doesn't give focus to the input bar, which it probably - # should. - # karxi: Test for tab changing? - if self.window().text.input: - if event.key() not in (QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown, - QtCore.Qt.Key_Up, QtCore.Qt.Key_Down): - self.window().text.input.keyPressEvent(event) - - super(ConsoleText, self).keyPressEvent(event) - - def mousePressEvent(self, event): - if event.button() == QtCore.Qt.LeftButton: - url = self.anchorAt(event.pos()) - if url != "": - # Skip memo/handle recognition - # NOTE: Ctrl+Click copies the URL. Maybe it should select it? - if event.modifiers() == QtCore.Qt.ControlModifier: - QtGui.QApplication.clipboard().setText(url) - else: - # This'll probably be removed. May change the lexer out. - QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode)) - - super(ConsoleText, self).mousePressEvent(event) - - def mouseMoveEvent(self, event): - # Change our cursor when we roll over links (anchors). - super(ConsoleText, self).mouseMoveEvent(event) - if self.anchorAt(event.pos()): - if self.viewport().cursor().shape != QtCore.Qt.PointingHandCursor: - self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) - else: - self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) - - def contextMenuEvent(self, event): - # This is almost certainly no longer necessary. - textMenu = self.createStandardContextMenu() - #~if self.textSelected: - #~ self.submitLogAction = QtGui.QAction("Submit to Pesterchum QDB", self) - #~ self.connect(self.submitLogAction, QtCore.SIGNAL('triggered()'), - #~ self, QtCore.SLOT('submitLog()')) - #~ textMenu.addAction(self.submitLogAction) - textMenu.exec_(event.globalPos()) - - -class ConsoleInput(QtGui.QLineEdit): - """The actual text entry box on a ConsoleWindow.""" - # I honestly feel like this could just be made a private class of - # ConsoleWindow, but...best not to overcomplicate things. - stylesheet_path = "convo/input/style" - - def __init__(self, theme, parent=None): - super(ConsoleInput, self).__init__(parent) - - self.changeTheme(theme) - - def changeTheme(self, theme): - self.setStyleSheet(theme[self.stylesheet_path]) - - def focusInEvent(self, event): - # We gained focus. Notify the parent window that this happened. - self.window().clearNewMessage() - self.window().text.area.textCursor().clearSelection() - - super(ConsoleInput, self).focusInEvent(event) - - def keyPressEvent(self, event): - evtkey = event.key() - parent = self.window() - - # If a key is pressed here, we're not idle.... - # NOTE: Do we really want everyone knowing we're around if we're - # messing around in the console? Hm. - parent.mainwindow.idler.time = 0 - - if evtkey == QtCore.Qt.Key_Up: - text = unicode(self.text()) - next = parent.text.history.next(text) - if next is not None: - self.setText(next) - elif evtkey == QtCore.Qt.Key_Down: - prev = parent.text.history.prev() - if prev is not None: - self.setText(prev) - elif evtkey in (QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown): - parent.text.area.keyPressEvent(event) - else: - super(ConsoleInput, self).keyPressEvent(event) diff --git a/convo.py b/convo.py index 3aa4daf..2828022 100644 --- a/convo.py +++ b/convo.py @@ -1,11 +1,11 @@ from string import Template import re import platform -import httplib, urllib +import http.client, urllib.request, urllib.parse, urllib.error from time import strftime from copy import copy from datetime import datetime, timedelta -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets from mood import Mood from dataobjs import PesterProfile, PesterHistory @@ -21,49 +21,42 @@ except ImportError: # Fall back on the old location - just in case from pnc.dep.attrdict import AttrDict -class PesterTabWindow(QtGui.QFrame): +class PesterTabWindow(QtWidgets.QFrame): def __init__(self, mainwindow, parent=None, convo="convo"): super(PesterTabWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.setFocusPolicy(QtCore.Qt.ClickFocus) self.mainwindow = mainwindow - self.tabs = QtGui.QTabBar(self) + self.tabs = QtWidgets.QTabBar(self) self.tabs.setMovable(True) self.tabs.setTabsClosable(True) - self.connect(self.tabs, QtCore.SIGNAL('currentChanged(int)'), - self, QtCore.SLOT('changeTab(int)')) - self.connect(self.tabs, QtCore.SIGNAL('tabCloseRequested(int)'), - self, QtCore.SLOT('tabClose(int)')) - self.connect(self.tabs, QtCore.SIGNAL('tabMoved(int, int)'), - self, QtCore.SLOT('tabMoved(int, int)')) + self.tabs.currentChanged[int].connect(self.changeTab) + self.tabs.tabCloseRequested[int].connect(self.tabClose) + self.tabs.tabMoved[int, int].connect(self.tabMoved) self.shortcuts = AttrDict() - self.shortcuts.tabNext = QtGui.QShortcut( + self.shortcuts.tabNext = QtWidgets.QShortcut( QtGui.QKeySequence('Ctrl+j'), self, context=QtCore.Qt.WidgetWithChildrenShortcut) - self.shortcuts.tabLast = QtGui.QShortcut( + self.shortcuts.tabLast = QtWidgets.QShortcut( QtGui.QKeySequence('Ctrl+k'), self, context=QtCore.Qt.WidgetWithChildrenShortcut) # Note that we use reversed keys here. - self.shortcuts.tabUp = QtGui.QShortcut( + self.shortcuts.tabUp = QtWidgets.QShortcut( QtGui.QKeySequence('Ctrl+PgDown'), self, context=QtCore.Qt.WidgetWithChildrenShortcut) - self.shortcuts.tabDn = QtGui.QShortcut( + self.shortcuts.tabDn = QtWidgets.QShortcut( QtGui.QKeySequence('Ctrl+PgUp'), self, context=QtCore.Qt.WidgetWithChildrenShortcut) - self.connect(self.shortcuts.tabNext, QtCore.SIGNAL('activated()'), - self, QtCore.SLOT('nudgeTabNext()')) - self.connect(self.shortcuts.tabUp, QtCore.SIGNAL('activated()'), - self, QtCore.SLOT('nudgeTabNext()')) - self.connect(self.shortcuts.tabLast, QtCore.SIGNAL('activated()'), - self, QtCore.SLOT('nudgeTabLast()')) - self.connect(self.shortcuts.tabDn, QtCore.SIGNAL('activated()'), - self, QtCore.SLOT('nudgeTabLast()')) + self.shortcuts.tabNext.activated.connect(self.nudgeTabNext) + self.shortcuts.tabUp.activated.connect(self.nudgeTabNext) + self.shortcuts.tabLast.activated.connect(self.nudgeTabLast) + self.shortcuts.tabDn.activated.connect(self.nudgeTabLast) self.initTheme(self.mainwindow.theme) - self.layout = QtGui.QVBoxLayout() + self.layout = QtWidgets.QVBoxLayout() self.layout.setContentsMargins(0,0,0,0) self.layout.addWidget(self.tabs) self.setLayout(self.layout) @@ -116,7 +109,7 @@ class PesterTabWindow(QtGui.QFrame): mods = event.modifiers() if ((mods & QtCore.Qt.ControlModifier) and keypress == QtCore.Qt.Key_Tab): - handles = self.convos.keys() + handles = list(self.convos.keys()) waiting = self.mainwindow.waitingMessages.waitingHandles() waitinghandles = list(set(handles) & set(waiting)) if len(waitinghandles) > 0: @@ -153,7 +146,7 @@ class PesterTabWindow(QtGui.QFrame): # The new index would be higher than the maximum; loop. nind = nind % ct # Otherwise, negative syntax should get it for us. - nind = range(ct)[nind] + nind = list(range(ct))[nind] # Change to the selected tab. # Note that this will send out the usual callbacks that handle # focusing and such. @@ -164,7 +157,7 @@ class PesterTabWindow(QtGui.QFrame): tabi = self.tabs.tabAt(event.pos()) if tabi < 0: tabi = self.tabs.currentIndex() - for h, i in self.tabIndices.items(): + for h, i in list(self.tabIndices.items()): if i == tabi: # Our index matches, grab the object using our handle. convo = self.convos[h] @@ -203,7 +196,7 @@ class PesterTabWindow(QtGui.QFrame): i = self.tabs.tabAt(self.mapFromGlobal(QtGui.QCursor.pos())) if i == -1: i = self.tabs.currentIndex() - handle = unicode(self.tabs.tabText(i)) + handle = str(self.tabs.tabText(i)) self.clearNewMessage(handle) def convoHasFocus(self, handle): i = self.tabIndices[handle] @@ -237,24 +230,24 @@ class PesterTabWindow(QtGui.QFrame): def changeTheme(self, theme): self.initTheme(theme) - for c in self.convos.values(): + for c in list(self.convos.values()): tabi = self.tabIndices[c.title()] self.tabs.setTabIcon(tabi, c.icon()) currenttabi = self.tabs.currentIndex() if currenttabi >= 0: - currentHandle = unicode(self.tabs.tabText(self.tabs.currentIndex())) + currentHandle = str(self.tabs.tabText(self.tabs.currentIndex())) self.setWindowIcon(self.convos[currentHandle].icon()) self.defaultTabTextColor = self.getTabTextColor() @QtCore.pyqtSlot(int) def tabClose(self, i): - handle = unicode(self.tabs.tabText(i)) + handle = str(self.tabs.tabText(i)) self.mainwindow.waitingMessages.messageAnswered(handle) convo = self.convos[handle] del self.convos[handle] del self.tabIndices[handle] self.tabs.removeTab(i) - for (h, j) in self.tabIndices.iteritems(): + for (h, j) in self.tabIndices.items(): if j > i: self.tabIndices[h] = j-1 self.layout.removeWidget(convo) @@ -264,7 +257,7 @@ class PesterTabWindow(QtGui.QFrame): return if self.currentConvo == convo: currenti = self.tabs.currentIndex() - currenth = unicode(self.tabs.tabText(currenti)) + currenth = str(self.tabs.tabText(currenti)) self.currentConvo = self.convos[currenth] self.currentConvo.raiseChat() @@ -275,7 +268,7 @@ class PesterTabWindow(QtGui.QFrame): if self.changedTab: self.changedTab = False return - handle = unicode(self.tabs.tabText(i)) + handle = str(self.tabs.tabText(i)) convo = self.convos[handle] if self.currentConvo: self.layout.removeWidget(self.currentConvo) @@ -310,7 +303,7 @@ class PesterMovie(QtGui.QMovie): if text.mainwindow.config.animations(): movie = self url = text.urls[movie].toString() - html = unicode(text.toHtml()) + html = str(text.toHtml()) if html.find(url) != -1: if text.hasTabs: i = text.tabobject.tabIndices[text.parent().title()] @@ -323,7 +316,7 @@ class PesterMovie(QtGui.QMovie): text.urls[movie], movie.currentPixmap()) text.setLineWrapColumnOrWidth(text.lineWrapColumnOrWidth()) -class PesterText(QtGui.QTextEdit): +class PesterText(QtWidgets.QTextEdit): def __init__(self, theme, parent=None): super(PesterText, self).__init__(parent) if hasattr(self.parent(), 'mainwindow'): @@ -339,33 +332,30 @@ class PesterText(QtGui.QTextEdit): self.setReadOnly(True) self.setMouseTracking(True) self.textSelected = False - self.connect(self, QtCore.SIGNAL('copyAvailable(bool)'), - self, QtCore.SLOT('textReady(bool)')) + self.copyAvailable[bool].connect(self.textReady) self.urls = {} for k in smiledict: self.addAnimation(QtCore.QUrl("smilies/%s" % (smiledict[k])), "smilies/%s" % (smiledict[k])) - self.connect(self.mainwindow, QtCore.SIGNAL('animationSetting(bool)'), - self, QtCore.SLOT('animateChanged(bool)')) + self.mainwindow.animationSetting[bool].connect(self.animateChanged) def addAnimation(self, url, fileName): movie = PesterMovie(self) movie.setFileName(fileName) movie.setCacheMode(QtGui.QMovie.CacheAll) if movie.frameCount() > 1: self.urls[movie] = url - movie.connect(movie, QtCore.SIGNAL('frameChanged(int)'), - movie, QtCore.SLOT('animate(int)')) + movie.frameChanged[int].connect(movie.animate) #movie.start() @QtCore.pyqtSlot(bool) def animateChanged(self, animate): if animate: for m in self.urls: - html = unicode(self.toHtml()) + html = str(self.toHtml()) if html.find(self.urls[m].toString()) != -1: if m.frameCount() > 1: m.start() else: for m in self.urls: - html = unicode(self.toHtml()) + html = str(self.toHtml()) if html.find(self.urls[m].toString()) != -1: if m.frameCount() > 1: m.stop() @@ -374,7 +364,7 @@ class PesterText(QtGui.QTextEdit): def textReady(self, ready): self.textSelected = ready def initTheme(self, theme): - if theme.has_key("convo/scrollbar"): + if "convo/scrollbar" in theme: self.setStyleSheet("QTextEdit { %s } QScrollBar:vertical { %s } QScrollBar::handle:vertical { %s } QScrollBar::add-line:vertical { %s } QScrollBar::sub-line:vertical { %s } QScrollBar:up-arrow:vertical { %s } QScrollBar:down-arrow:vertical { %s }" % (theme["convo/textarea/style"], theme["convo/scrollbar/style"], theme["convo/scrollbar/handle"], theme["convo/scrollbar/downarrow"], theme["convo/scrollbar/uparrow"], theme["convo/scrollbar/uarrowstyle"], theme["convo/scrollbar/darrowstyle"] )) else: self.setStyleSheet("QTextEdit { %s }" % (theme["convo/textarea/style"])) @@ -472,7 +462,7 @@ class PesterText(QtGui.QTextEdit): sb.setValue(sb.maximum()) def focusInEvent(self, event): self.parent().clearNewMessage() - QtGui.QTextEdit.focusInEvent(self, event) + QtWidgets.QTextEdit.focusInEvent(self, event) def isBot(self, *args, **kwargs): return self.parent().isBot(*args, **kwargs) @@ -499,16 +489,16 @@ class PesterText(QtGui.QTextEdit): if url[0] == "#" and url != "#pesterchum": self.parent().mainwindow.showMemos(url[1:]) elif url[0] == "@": - handle = unicode(url[1:]) + handle = str(url[1:]) self.parent().mainwindow.newConversation(handle) else: if event.modifiers() == QtCore.Qt.ControlModifier: - QtGui.QApplication.clipboard().setText(url) + QtWidgets.QApplication.clipboard().setText(url) else: QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode)) - QtGui.QTextEdit.mousePressEvent(self, event) + QtWidgets.QTextEdit.mousePressEvent(self, event) def mouseMoveEvent(self, event): - QtGui.QTextEdit.mouseMoveEvent(self, event) + QtWidgets.QTextEdit.mouseMoveEvent(self, event) if self.anchorAt(event.pos()): if self.viewport().cursor().shape != QtCore.Qt.PointingHandCursor: self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) @@ -535,22 +525,21 @@ class PesterText(QtGui.QTextEdit): textdoc = QtGui.QTextDocument() textdoc.setHtml(htmldata) logdata = "%s\n%s" % (self.submitLogTitle(), textdoc.toPlainText()) - self.sending = QtGui.QDialog(self) - layout = QtGui.QVBoxLayout() - self.sending.sendinglabel = QtGui.QLabel("S3ND1NG...", self.sending) - cancelbutton = QtGui.QPushButton("OK", self.sending) - self.sending.connect(cancelbutton, QtCore.SIGNAL('clicked()'), - self.sending, QtCore.SLOT('close()')) + self.sending = QtWidgets.QDialog(self) + layout = QtWidgets.QVBoxLayout() + self.sending.sendinglabel = QtWidgets.QLabel("S3ND1NG...", self.sending) + cancelbutton = QtWidgets.QPushButton("OK", self.sending) + cancelbutton.clicked.connect(self.sending.close) layout.addWidget(self.sending.sendinglabel) layout.addWidget(cancelbutton) self.sending.setLayout(layout) self.sending.show() - params = urllib.urlencode({'quote': logdata, 'do': "add"}) + params = urllib.parse.urlencode({'quote': logdata, 'do': "add"}) headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} try: pass - hconn = httplib.HTTPConnection('qdb.pesterchum.net', 80, + hconn = http.client.HTTPConnection('qdb.pesterchum.net', 80, timeout=15) hconn.request("POST", "/index.php", params, headers) response = hconn.getresponse() @@ -563,7 +552,7 @@ class PesterText(QtGui.QTextEdit): self.sending.sendinglabel.setText("F41L3D: %s" % (e)) del self.sending -class PesterInput(QtGui.QLineEdit): +class PesterInput(QtWidgets.QLineEdit): stylesheet_path = "convo/input/style" def __init__(self, theme, parent=None): super(PesterInput, self).__init__(parent) @@ -576,7 +565,7 @@ class PesterInput(QtGui.QLineEdit): super(PesterInput, self).focusInEvent(event) def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Up: - text = unicode(self.text()) + text = str(self.text()) next = self.parent().history.next(text) if next is not None: self.setText(next) @@ -589,7 +578,7 @@ class PesterInput(QtGui.QLineEdit): self.parent().mainwindow.idler.time = 0 super(PesterInput, self).keyPressEvent(event) -class PesterConvo(QtGui.QFrame): +class PesterConvo(QtWidgets.QFrame): def __init__(self, chum, initiated, mainwindow, parent=None): super(PesterConvo, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) @@ -605,20 +594,19 @@ class PesterConvo(QtGui.QFrame): t = Template(self.mainwindow.theme["convo/chumlabel/text"]) - self.chumLabel = QtGui.QLabel(t.safe_substitute(handle=chum.handle), self) + self.chumLabel = QtWidgets.QLabel(t.safe_substitute(handle=chum.handle), self) self.chumLabel.setStyleSheet(self.mainwindow.theme["convo/chumlabel/style"]) self.chumLabel.setAlignment(self.aligndict["h"][self.mainwindow.theme["convo/chumlabel/align/h"]] | self.aligndict["v"][self.mainwindow.theme["convo/chumlabel/align/v"]]) self.chumLabel.setMaximumHeight(self.mainwindow.theme["convo/chumlabel/maxheight"]) self.chumLabel.setMinimumHeight(self.mainwindow.theme["convo/chumlabel/minheight"]) - self.chumLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) + self.chumLabel.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)) self.textArea = PesterText(self.mainwindow.theme, self) self.textInput = PesterInput(self.mainwindow.theme, self) self.textInput.setFocus() - self.connect(self.textInput, QtCore.SIGNAL('returnPressed()'), - self, QtCore.SLOT('sentMessage()')) + self.textInput.returnPressed.connect(self.sentMessage) - self.layout = QtGui.QVBoxLayout() + self.layout = QtWidgets.QVBoxLayout() self.layout.addWidget(self.chumLabel) self.layout.addWidget(self.textArea) self.layout.addWidget(self.textInput) @@ -629,31 +617,24 @@ class PesterConvo(QtGui.QFrame): self.setLayout(self.layout) - self.optionsMenu = QtGui.QMenu(self) + self.optionsMenu = QtWidgets.QMenu(self) self.optionsMenu.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) - self.addChumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self) - self.connect(self.addChumAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('addThisChum()')) - self.blockAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"], self) - self.connect(self.blockAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('blockThisChum()')) - self.quirksOff = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"], self) + self.addChumAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self) + self.addChumAction.triggered.connect(self.addThisChum) + self.blockAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"], self) + self.blockAction.triggered.connect(self.blockThisChum) + self.quirksOff = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"], self) self.quirksOff.setCheckable(True) - self.connect(self.quirksOff, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleQuirks(bool)')) - self.oocToggle = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/ooc"], self) + self.quirksOff.toggled[bool].connect(self.toggleQuirks) + self.oocToggle = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/ooc"], self) self.oocToggle.setCheckable(True) - self.connect(self.oocToggle, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleOOC(bool)')) - self.unblockchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"], self) - self.connect(self.unblockchum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('unblockChumSlot()')) - self.reportchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/report"], self) - self.connect(self.reportchum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('reportThisChum()')) - self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self) - self.connect(self.logchum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('openChumLogs()')) + self.oocToggle.toggled[bool].connect(self.toggleOOC) + self.unblockchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"], self) + self.unblockchum.triggered.connect(self.unblockChumSlot) + self.reportchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/report"], self) + self.reportchum.triggered.connect(self.reportThisChum) + self.logchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self) + self.logchum.triggered.connect(self.openChumLogs) # For this, we'll want to use setChecked to toggle these so they match # the user's setting. Alternately (better), use a tristate checkbox, so @@ -661,20 +642,17 @@ class PesterConvo(QtGui.QFrame): # Easiest solution: Implement a 'Mute' option that overrides all # notifications for that window, save for mentions. # TODO: Look into setting up theme support here. - self._beepToggle = QtGui.QAction("Beep on Message", self) + self._beepToggle = QtWidgets.QAction("Beep on Message", self) self._beepToggle.setCheckable(True) - self.connect(self._beepToggle, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleBeep(bool)')) + self._beepToggle.toggled[bool].connect(self.toggleBeep) - self._flashToggle = QtGui.QAction("Flash on Message", self) + self._flashToggle = QtWidgets.QAction("Flash on Message", self) self._flashToggle.setCheckable(True) - self.connect(self._flashToggle, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleFlash(bool)')) + self._flashToggle.toggled[bool].connect(self.toggleFlash) - self._muteToggle = QtGui.QAction("Mute Notifications", self) + self._muteToggle = QtWidgets.QAction("Mute Notifications", self) self._muteToggle.setCheckable(True) - self.connect(self._muteToggle, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleMute(bool)')) + self._muteToggle.toggled[bool].connect(self.toggleMute) self.optionsMenu.addAction(self.quirksOff) self.optionsMenu.addAction(self.oocToggle) @@ -755,7 +733,7 @@ class PesterConvo(QtGui.QFrame): def updateColor(self, color): self.chum.color = color def addMessage(self, msg, me=True): - if type(msg) in [str, unicode]: + if type(msg) in [str, str]: lexmsg = lexMessage(msg) else: lexmsg = msg @@ -870,7 +848,7 @@ class PesterConvo(QtGui.QFrame): self.chumLabel.setAlignment(self.aligndict["h"][self.mainwindow.theme["convo/chumlabel/align/h"]] | self.aligndict["v"][self.mainwindow.theme["convo/chumlabel/align/v"]]) self.chumLabel.setMaximumHeight(self.mainwindow.theme["convo/chumlabel/maxheight"]) self.chumLabel.setMinimumHeight(self.mainwindow.theme["convo/chumlabel/minheight"]) - self.chumLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)) + self.chumLabel.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)) self.quirksOff.setText(self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"]) self.addChumAction.setText(self.mainwindow.theme["main/menus/rclickchumlist/addchum"]) self.blockAction.setText(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"]) @@ -886,7 +864,7 @@ class PesterConvo(QtGui.QFrame): # Offloaded to another function, like its sisters. # Fetch the raw text from the input box. text = self.textInput.text() - text = unicode(self.textInput.text()) + text = str(self.textInput.text()) return parsetools.kxhandleInput(self, text, flavor="convo") @@ -912,8 +890,7 @@ class PesterConvo(QtGui.QFrame): def openChumLogs(self): currentChum = self.chum.handle self.mainwindow.chumList.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow) - self.connect(self.mainwindow.chumList.pesterlogviewer, QtCore.SIGNAL('rejected()'), - self.mainwindow.chumList, QtCore.SLOT('closeActiveLog()')) + self.mainwindow.chumList.pesterlogviewer.rejected.connect(self.mainwindow.chumList.closeActiveLog) self.mainwindow.chumList.pesterlogviewer.show() self.mainwindow.chumList.pesterlogviewer.raise_() self.mainwindow.chumList.pesterlogviewer.activateWindow() @@ -930,8 +907,8 @@ class PesterConvo(QtGui.QFrame): def toggleMute(self, toggled): self.notifications_muted = toggled - messageSent = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - windowClosed = QtCore.pyqtSignal(QtCore.QString) + messageSent = QtCore.pyqtSignal('QString', 'QString') + windowClosed = QtCore.pyqtSignal('QString') aligndict = {"h": {"center": QtCore.Qt.AlignHCenter, "left": QtCore.Qt.AlignLeft, diff --git a/dataobjs.py b/dataobjs.py index 0ea6c58..f459126 100644 --- a/dataobjs.py +++ b/dataobjs.py @@ -1,4 +1,4 @@ -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui from datetime import * import re import random @@ -111,7 +111,7 @@ class pesterQuirks(object): newlist = [] for (i, o) in enumerate(lexed): - if type(o) not in [str, unicode]: + if type(o) not in [str, str]: if i == 0: string = " " for p in prefix: @@ -135,7 +135,7 @@ class pesterQuirks(object): final = [] for n in newlist: - if type(n) in [str, unicode]: + if type(n) in [str, str]: final.extend(lexMessage(n)) else: final.append(n) @@ -191,9 +191,9 @@ class PesterProfile(object): def plaindict(self): return (self.handle, {"handle": self.handle, "mood": self.mood.name(), - "color": unicode(self.color.name()), - "group": unicode(self.group), - "notes": unicode(self.notes)}) + "color": str(self.color.name()), + "group": str(self.group), + "notes": str(self.notes)}) def blocked(self, config): return self.handle in config.getBlocklist() @@ -238,7 +238,7 @@ class PesterProfile(object): (opchum.colorhtml(), opinit, self.colorhtml(), ", ".join(initials)) else: return "%s banned %s from responding to memo: [%s]." % \ - (opchum.colorhtml(), opinit, self.colorhtml(), ", ".join(initials), unicode(reason)) + (opchum.colorhtml(), opinit, self.colorhtml(), ", ".join(initials), str(reason)) else: initials = timeGrammar.pcf+self.initials()+timeGrammar.number if opchum.handle == reason: @@ -246,7 +246,7 @@ class PesterProfile(object): (opchum.colorhtml(), opinit, self.colorhtml(), initials) else: return "%s banned %s from responding to memo: [%s]." % \ - (opchum.colorhtml(), opinit, self.colorhtml(), initials, unicode(reason)) + (opchum.colorhtml(), opinit, self.colorhtml(), initials, str(reason)) def memopermabanmsg(self, opchum, opgrammar, syscolor, timeGrammar): initials = timeGrammar.pcf+self.initials()+timeGrammar.number opinit = opgrammar.pcf+opchum.initials()+opgrammar.number diff --git a/generic.py b/generic.py index 2c7453e..219708b 100644 --- a/generic.py +++ b/generic.py @@ -1,4 +1,4 @@ -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets from datetime import timedelta class mysteryTime(timedelta): @@ -17,7 +17,7 @@ class CaseInsensitiveDict(dict): def __contains__(self, key): return super(CaseInsensitiveDict, self).__contains__(key.lower()) def has_key(self, key): - return super(CaseInsensitiveDict, self).has_key(key.lower()) + return key.lower() in super(CaseInsensitiveDict, self) def __delitem__(self, key): super(CaseInsensitiveDict, self).__delitem__(key.lower()) @@ -28,7 +28,7 @@ class PesterList(list): class PesterIcon(QtGui.QIcon): def __init__(self, *x): super(PesterIcon, self).__init__(x[0]) - if type(x[0]) in [str, unicode]: + if type(x[0]) in [str, str]: self.icon_pixmap = QtGui.QPixmap(x[0]) else: self.icon_pixmap = None @@ -41,7 +41,7 @@ class PesterIcon(QtGui.QIcon): except IndexError: return None -class RightClickList(QtGui.QListWidget): +class RightClickList(QtWidgets.QListWidget): def contextMenuEvent(self, event): #fuckin Qt if event.reason() == QtGui.QContextMenuEvent.Mouse: @@ -53,7 +53,7 @@ class RightClickList(QtGui.QListWidget): def getOptionsMenu(self): return self.optionsMenu -class RightClickTree(QtGui.QTreeWidget): +class RightClickTree(QtWidgets.QTreeWidget): def contextMenuEvent(self, event): if event.reason() == QtGui.QContextMenuEvent.Mouse: listing = self.itemAt(event.pos()) @@ -64,49 +64,47 @@ class RightClickTree(QtGui.QTreeWidget): def getOptionsMenu(self): return self.optionsMenu -class MultiTextDialog(QtGui.QDialog): +class MultiTextDialog(QtWidgets.QDialog): def __init__(self, title, parent, *queries): super(MultiTextDialog, self).__init__(parent) self.setWindowTitle(title) if len(queries) == 0: return self.inputs = {} - layout_1 = QtGui.QHBoxLayout() + layout_1 = QtWidgets.QHBoxLayout() for d in queries: label = d["label"] inputname = d["inputname"] value = d.get("value", "") - l = QtGui.QLabel(label, self) + l = QtWidgets.QLabel(label, self) layout_1.addWidget(l) - self.inputs[inputname] = QtGui.QLineEdit(value, self) + self.inputs[inputname] = QtWidgets.QLineEdit(value, self) layout_1.addWidget(self.inputs[inputname]) - self.ok = QtGui.QPushButton("OK", self) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('accept()')) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_ok = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.accept) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + layout_ok = QtWidgets.QHBoxLayout() layout_ok.addWidget(self.cancel) layout_ok.addWidget(self.ok) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addLayout(layout_1) layout_0.addLayout(layout_ok) self.setLayout(layout_0) def getText(self): r = self.exec_() - if r == QtGui.QDialog.Accepted: + if r == QtWidgets.QDialog.Accepted: retval = {} - for (name, widget) in self.inputs.iteritems(): - retval[name] = unicode(widget.text()) + for (name, widget) in self.inputs.items(): + retval[name] = str(widget.text()) return retval else: return None -class MovingWindow(QtGui.QFrame): +class MovingWindow(QtWidgets.QFrame): def __init__(self, *x, **y): super(MovingWindow, self).__init__(*x, **y) self.moving = None @@ -133,7 +131,7 @@ class NoneSound(object): def play(self): pass def setVolume(self, v): pass -class WMButton(QtGui.QPushButton): +class WMButton(QtWidgets.QPushButton): def __init__(self, icon, parent=None): super(WMButton, self).__init__(icon, "", parent) self.setIconSize(icon.realsize()) diff --git a/irc.py b/irc.py index 09ced40..3449e1b 100644 --- a/irc.py +++ b/irc.py @@ -1,4 +1,4 @@ -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui from oyoyo.client import IRCClient from oyoyo.cmdhandler import DefaultCommandHandler from oyoyo import helpers, services @@ -13,6 +13,12 @@ from generic import PesterList from version import _pcVersion import ostools +try: + QString = unicode +except NameError: + # Python 3 + QString = str + if ostools.isOSXBundle(): logging.basicConfig(level=logging.WARNING) else: @@ -39,7 +45,7 @@ class PesterIRC(QtCore.QThread): def run(self): try: self.IRCConnect() - except socket.error, se: + except socket.error as se: self.stopIRC = se return while 1: @@ -47,12 +53,12 @@ class PesterIRC(QtCore.QThread): try: logging.debug("updateIRC()") res = self.updateIRC() - except socket.timeout, se: + except socket.timeout as se: logging.debug("timeout in thread %s" % (self)) self.cli.close() self.stopIRC = se return - except socket.error, se: + except socket.error as se: if self.registeredIRC: self.stopIRC = None else: @@ -74,13 +80,13 @@ class PesterIRC(QtCore.QThread): @QtCore.pyqtSlot() def updateIRC(self): try: - res = self.conn.next() - except socket.timeout, se: + res = next(self.conn) + except socket.timeout as se: if self.registeredIRC: return True else: raise se - except socket.error, se: + except socket.error as se: raise se except StopIteration: self.conn = self.cli.conn() @@ -98,18 +104,18 @@ class PesterIRC(QtCore.QThread): @QtCore.pyqtSlot(PesterList) def getMoods(self, chums): self.cli.command_handler.getMood(*chums) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def sendNotice(self, text, handle): - h = unicode(handle) - t = unicode(text) + h = str(handle) + t = str(text) try: helpers.notice(self.cli, h, t) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def sendMessage(self, text, handle): - h = unicode(handle) - textl = [unicode(text)] + h = str(handle) + textl = [str(text)] def splittext(l): if len(l[0]) > 450: space = l[0].rfind(" ", 0,430) @@ -152,18 +158,18 @@ class PesterIRC(QtCore.QThread): helpers.msg(self.cli, h, t) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString, bool) + @QtCore.pyqtSlot(QString, bool) def startConvo(self, handle, initiated): - h = unicode(handle) + h = str(handle) try: if initiated: helpers.msg(self.cli, h, "PESTERCHUM:BEGIN") helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd())) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def endConvo(self, handle): - h = unicode(handle) + h = str(handle) try: helpers.msg(self.cli, h, "PESTERCHUM:CEASE") except socket.error: @@ -191,28 +197,28 @@ class PesterIRC(QtCore.QThread): @QtCore.pyqtSlot() def updateColor(self): me = self.mainwindow.profile() - for h in self.mainwindow.convos.keys(): + for h in list(self.mainwindow.convos.keys()): try: helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd())) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def blockedChum(self, handle): - h = unicode(handle) + h = str(handle) try: helpers.msg(self.cli, h, "PESTERCHUM:BLOCK") except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def unblockedChum(self, handle): - h = unicode(handle) + h = str(handle) try: helpers.msg(self.cli, h, "PESTERCHUM:UNBLOCK") except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def requestNames(self, channel): - c = unicode(channel) + c = str(channel) try: helpers.names(self.cli, c) except socket.error: @@ -223,60 +229,60 @@ class PesterIRC(QtCore.QThread): helpers.channel_list(self.cli) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def joinChannel(self, channel): - c = unicode(channel) + c = str(channel) try: helpers.join(self.cli, c) helpers.mode(self.cli, c, "", None) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def leftChannel(self, channel): - c = unicode(channel) + c = str(channel) try: helpers.part(self.cli, c) self.cli.command_handler.joined = False except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def kickUser(self, handle, channel): l = handle.split(":") - c = unicode(channel) - h = unicode(l[0]) + c = str(channel) + h = str(l[0]) if len(l) > 1: - reason = unicode(l[1]) + reason = str(l[1]) if len(l) > 2: for x in l[2:]: - reason += unicode(":") + unicode(x) + reason += str(":") + str(x) else: reason = "" try: helpers.kick(self.cli, h, c, reason) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString, QString) def setChannelMode(self, channel, mode, command): - c = unicode(channel) - m = unicode(mode) - cmd = unicode(command) + c = str(channel) + m = str(mode) + cmd = str(command) if cmd == "": cmd = None try: helpers.mode(self.cli, c, m, cmd) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def channelNames(self, channel): - c = unicode(channel) + c = str(channel) try: helpers.names(self.cli, c) except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def inviteChum(self, handle, channel): - h = unicode(handle) - c = unicode(channel) + h = str(handle) + c = str(channel) try: helpers.invite(self.cli, h, c) except socket.error: @@ -299,34 +305,34 @@ class PesterIRC(QtCore.QThread): except socket.error: self.setConnectionBroken() - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def killSomeQuirks(self, channel, handle): - c = unicode(channel) - h = unicode(handle) + c = str(channel) + h = str(handle) try: helpers.ctcp(self.cli, c, "NOQUIRKS", h) except socket.error: self.setConnectionBroken() - moodUpdated = QtCore.pyqtSignal(QtCore.QString, Mood) - colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor) - messageReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - memoReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString) - noticeReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - inviteReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - timeCommand = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString) - namesReceived = QtCore.pyqtSignal(QtCore.QString, PesterList) + moodUpdated = QtCore.pyqtSignal('QString', Mood) + colorUpdated = QtCore.pyqtSignal('QString', QtGui.QColor) + messageReceived = QtCore.pyqtSignal('QString', 'QString') + memoReceived = QtCore.pyqtSignal('QString', 'QString', 'QString') + noticeReceived = QtCore.pyqtSignal('QString', 'QString') + inviteReceived = QtCore.pyqtSignal('QString', 'QString') + timeCommand = QtCore.pyqtSignal('QString', 'QString', 'QString') + namesReceived = QtCore.pyqtSignal('QString', PesterList) channelListReceived = QtCore.pyqtSignal(PesterList) - nickCollision = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - myHandleChanged = QtCore.pyqtSignal(QtCore.QString) - chanInviteOnly = QtCore.pyqtSignal(QtCore.QString) - modesUpdated = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) + nickCollision = QtCore.pyqtSignal('QString', 'QString') + myHandleChanged = QtCore.pyqtSignal('QString') + chanInviteOnly = QtCore.pyqtSignal('QString') + modesUpdated = QtCore.pyqtSignal('QString', 'QString') connected = QtCore.pyqtSignal() - userPresentUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, - QtCore.QString) - cannotSendToChan = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) + userPresentUpdate = QtCore.pyqtSignal('QString', 'QString', + 'QString') + cannotSendToChan = QtCore.pyqtSignal('QString', 'QString') tooManyPeeps = QtCore.pyqtSignal() - quirkDisable = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString) + quirkDisable = QtCore.pyqtSignal('QString', 'QString', 'QString') class PesterHandler(DefaultCommandHandler): def notice(self, nick, chan, msg): diff --git a/libs/feedparser.py b/libs/feedparser.py index 91bec85..127c14f 100755 --- a/libs/feedparser.py +++ b/libs/feedparser.py @@ -66,11 +66,12 @@ TIDY_MARKUP = 0 PREFERRED_TIDY_INTERFACES = ["uTidy", "mxTidy"] # ---------- required modules (should come with any Python distribution) ---------- -import sgmllib, re, sys, copy, urlparse, time, rfc822, types, cgi, urllib, urllib2 +import sgmllib, re, sys, copy, urllib.parse, time, rfc822, types, cgi, urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse +# We *really* need to find a proper alternative for smgllib try: - from cStringIO import StringIO as _StringIO + from io import StringIO as _StringIO except: - from StringIO import StringIO as _StringIO + from io import StringIO as _StringIO # ---------- optional modules (feedparser will work without these, but with reduced functionality) ---------- @@ -191,7 +192,7 @@ class FeedParserDict(UserDict): if key == 'categories': return [(tag['scheme'], tag['term']) for tag in UserDict.__getitem__(self, 'tags')] realkey = self.keymap.get(key, key) - if type(realkey) == types.ListType: + if type(realkey) == list: for k in realkey: if UserDict.has_key(self, k): return UserDict.__getitem__(self, k) @@ -200,21 +201,21 @@ class FeedParserDict(UserDict): return UserDict.__getitem__(self, realkey) def __setitem__(self, key, value): - for k in self.keymap.keys(): + for k in list(self.keymap.keys()): if key == k: key = self.keymap[k] - if type(key) == types.ListType: + if type(key) == list: key = key[0] return UserDict.__setitem__(self, key, value) def get(self, key, default=None): - if self.has_key(key): + if key in self: return self[key] else: return default def setdefault(self, key, value): - if not self.has_key(key): + if key not in self: self[key] = value return self[key] @@ -233,7 +234,7 @@ class FeedParserDict(UserDict): assert not key.startswith('_') return self.__getitem__(key) except: - raise AttributeError, "object has no attribute '%s'" % key + raise AttributeError("object has no attribute '%s'" % key) def __setattr__(self, key, value): if key.startswith('_') or key == 'data': @@ -242,7 +243,7 @@ class FeedParserDict(UserDict): return self.__setitem__(key, value) def __contains__(self, key): - return self.has_key(key) + return key in self def zopeCompatibilityHack(): global FeedParserDict @@ -277,13 +278,13 @@ def _ebcdic_to_ascii(s): ) import string _ebcdic_to_ascii_map = string.maketrans( \ - ''.join(map(chr, range(256))), ''.join(map(chr, emap))) + ''.join(map(chr, list(range(256)))), ''.join(map(chr, emap))) return s.translate(_ebcdic_to_ascii_map) _urifixer = re.compile('^([A-Za-z][A-Za-z0-9+-.]*://)(/*)(.*?)') def _urljoin(base, uri): uri = _urifixer.sub(r'\1\3', uri) - return urlparse.urljoin(base, uri) + return urllib.parse.urljoin(base, uri) class _FeedParserMixin: namespaces = {'': '', @@ -357,7 +358,7 @@ class _FeedParserMixin: def __init__(self, baseuri=None, baselang=None, encoding='utf-8'): if _debug: sys.stderr.write('initializing FeedParser\n') if not self._matchnamespaces: - for k, v in self.namespaces.items(): + for k, v in list(self.namespaces.items()): self._matchnamespaces[k.lower()] = v self.feeddata = FeedParserDict() # feed-level data self.encoding = encoding # character encoding @@ -420,7 +421,7 @@ class _FeedParserMixin: self.trackNamespace(None, uri) # track inline content - if self.incontent and self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'): + if self.incontent and 'type' in self.contentparams and not self.contentparams.get('type', 'xml').endswith('xml'): # element declared itself as escaped markup, but it isn't really self.contentparams['type'] = 'application/xhtml+xml' if self.incontent and self.contentparams.get('type') == 'application/xhtml+xml': @@ -436,7 +437,7 @@ class _FeedParserMixin: return self.handle_data('<%s%s>' % (tag, ''.join([' %s="%s"' % t for t in attrs])), escape=0) # match namespaces - if tag.find(':') <> -1: + if tag.find(':') != -1: prefix, suffix = tag.split(':', 1) else: prefix, suffix = '', tag @@ -461,7 +462,7 @@ class _FeedParserMixin: def unknown_endtag(self, tag): if _debug: sys.stderr.write('end %s\n' % tag) # match namespaces - if tag.find(':') <> -1: + if tag.find(':') != -1: prefix, suffix = tag.split(':', 1) else: prefix, suffix = '', tag @@ -478,7 +479,7 @@ class _FeedParserMixin: self.pop(prefix + suffix) # track inline content - if self.incontent and self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'): + if self.incontent and 'type' in self.contentparams and not self.contentparams.get('type', 'xml').endswith('xml'): # element declared itself as escaped markup, but it isn't really self.contentparams['type'] = 'application/xhtml+xml' if self.incontent and self.contentparams.get('type') == 'application/xhtml+xml': @@ -506,7 +507,7 @@ class _FeedParserMixin: c = int(ref[1:], 16) else: c = int(ref) - text = unichr(c).encode('utf-8') + text = chr(c).encode('utf-8') self.elementstack[-1][2].append(text) def handle_entityref(self, ref): @@ -518,16 +519,16 @@ class _FeedParserMixin: else: # entity resolution graciously donated by Aaron Swartz def name2cp(k): - import htmlentitydefs + import html.entities if hasattr(htmlentitydefs, 'name2codepoint'): # requires Python 2.3 - return htmlentitydefs.name2codepoint[k] - k = htmlentitydefs.entitydefs[k] + return html.entities.name2codepoint[k] + k = html.entities.entitydefs[k] if k.startswith('&#') and k.endswith(';'): return int(k[2:-1]) # not in latin-1 return ord(k) try: name2cp(ref) except KeyError: text = '&%s;' % ref - else: text = unichr(name2cp(ref)).encode('utf-8') + else: text = chr(name2cp(ref)).encode('utf-8') self.elementstack[-1][2].append(text) def handle_data(self, text, escape=1): @@ -579,11 +580,11 @@ class _FeedParserMixin: self.version = 'rss10' if loweruri == 'http://www.w3.org/2005/atom' and not self.version: self.version = 'atom10' - if loweruri.find('backend.userland.com/rss') <> -1: + if loweruri.find('backend.userland.com/rss') != -1: # match any backend.userland.com namespace uri = 'http://backend.userland.com/rss' loweruri = uri - if self._matchnamespaces.has_key(loweruri): + if loweruri in self._matchnamespaces: self.namespacemap[prefix] = self._matchnamespaces[loweruri] self.namespacesInUse[self._matchnamespaces[loweruri]] = uri else: @@ -645,9 +646,9 @@ class _FeedParserMixin: if element in self.can_contain_dangerous_markup: output = _sanitizeHTML(output, self.encoding) - if self.encoding and type(output) != type(u''): + if self.encoding and type(output) != type(''): try: - output = unicode(output, self.encoding) + output = str(output, self.encoding) except: pass @@ -704,7 +705,7 @@ class _FeedParserMixin: def _mapToStandardPrefix(self, name): colonpos = name.find(':') - if colonpos <> -1: + if colonpos != -1: prefix = name[:colonpos] suffix = name[colonpos+1:] prefix = self.namespacemap.get(prefix, prefix) @@ -767,11 +768,11 @@ class _FeedParserMixin: _start_feedinfo = _start_channel def _cdf_common(self, attrsD): - if attrsD.has_key('lastmod'): + if 'lastmod' in attrsD: self._start_modified({}) self.elementstack[-1][-1] = attrsD['lastmod'] self._end_modified() - if attrsD.has_key('href'): + if 'href' in attrsD: self._start_link({}) self.elementstack[-1][-1] = attrsD['href'] self._end_link() @@ -1147,7 +1148,7 @@ class _FeedParserMixin: attrsD.setdefault('rel', 'alternate') attrsD.setdefault('type', 'text/html') attrsD = self._itsAnHrefDamnIt(attrsD) - if attrsD.has_key('href'): + if 'href' in attrsD: attrsD['href'] = self.resolveURI(attrsD['href']) expectingText = self.infeed or self.inentry or self.insource context = self._getContext() @@ -1155,7 +1156,7 @@ class _FeedParserMixin: context['links'].append(FeedParserDict(attrsD)) if attrsD['rel'] == 'enclosure': self._start_enclosure(attrsD) - if attrsD.has_key('href'): + if 'href' in attrsD: expectingText = 0 if (attrsD.get('rel') == 'alternate') and (self.mapContentType(attrsD.get('type')) in self.html_types): context['link'] = attrsD['href'] @@ -1178,7 +1179,7 @@ class _FeedParserMixin: def _end_guid(self): value = self.pop('id') - self._save('guidislink', self.guidislink and not self._getContext().has_key('link')) + self._save('guidislink', self.guidislink and 'link' not in self._getContext()) if self.guidislink: # guid acts as link, but only if 'ispermalink' is not present or is 'true', # and only if the item doesn't already have a link element @@ -1201,7 +1202,7 @@ class _FeedParserMixin: def _start_description(self, attrsD): context = self._getContext() - if context.has_key('summary'): + if 'summary' in context: self._summaryKey = 'content' self._start_content(attrsD) else: @@ -1234,7 +1235,7 @@ class _FeedParserMixin: def _start_generator(self, attrsD): if attrsD: attrsD = self._itsAnHrefDamnIt(attrsD) - if attrsD.has_key('href'): + if 'href' in attrsD: attrsD['href'] = self.resolveURI(attrsD['href']) self._getContext()['generator_detail'] = FeedParserDict(attrsD) self.push('generator', 1) @@ -1242,7 +1243,7 @@ class _FeedParserMixin: def _end_generator(self): value = self.pop('generator') context = self._getContext() - if context.has_key('generator_detail'): + if 'generator_detail' in context: context['generator_detail']['name'] = value def _start_admin_generatoragent(self, attrsD): @@ -1262,7 +1263,7 @@ class _FeedParserMixin: def _start_summary(self, attrsD): context = self._getContext() - if context.has_key('summary'): + if 'summary' in context: self._summaryKey = 'content' self._start_content(attrsD) else: @@ -1352,7 +1353,7 @@ if _XML_AVAILABLE: def startElementNS(self, name, qname, attrs): namespace, localname = name lowernamespace = str(namespace or '').lower() - if lowernamespace.find('backend.userland.com/rss') <> -1: + if lowernamespace.find('backend.userland.com/rss') != -1: # match any backend.userland.com namespace namespace = 'http://backend.userland.com/rss' lowernamespace = namespace @@ -1361,12 +1362,12 @@ if _XML_AVAILABLE: else: givenprefix = None prefix = self._matchnamespaces.get(lowernamespace, givenprefix) - if givenprefix and (prefix == None or (prefix == '' and lowernamespace == '')) and not self.namespacesInUse.has_key(givenprefix): - raise UndeclaredNamespace, "'%s' is not associated with a namespace" % givenprefix + if givenprefix and (prefix == None or (prefix == '' and lowernamespace == '')) and givenprefix not in self.namespacesInUse: + raise UndeclaredNamespace("'%s' is not associated with a namespace" % givenprefix) if prefix: localname = prefix + ':' + localname localname = str(localname).lower() - if _debug: sys.stderr.write('startElementNS: qname = %s, namespace = %s, givenprefix = %s, prefix = %s, attrs = %s, localname = %s\n' % (qname, namespace, givenprefix, prefix, attrs.items(), localname)) + if _debug: sys.stderr.write('startElementNS: qname = %s, namespace = %s, givenprefix = %s, prefix = %s, attrs = %s, localname = %s\n' % (qname, namespace, givenprefix, prefix, list(attrs.items()), localname)) # qname implementation is horribly broken in Python 2.1 (it # doesn't report any), and slightly broken in Python 2.2 (it @@ -1376,7 +1377,7 @@ if _XML_AVAILABLE: # at all). Thanks to MatejC for helping me test this and # tirelessly telling me that it didn't work yet. attrsD = {} - for (namespace, attrlocalname), attrvalue in attrs._attrs.items(): + for (namespace, attrlocalname), attrvalue in list(attrs._attrs.items()): lowernamespace = (namespace or '').lower() prefix = self._matchnamespaces.get(lowernamespace, '') if prefix: @@ -1384,7 +1385,7 @@ if _XML_AVAILABLE: attrsD[str(attrlocalname).lower()] = attrvalue for qname in attrs.getQNames(): attrsD[str(qname).lower()] = attrs.getValueByQName(qname) - self.unknown_starttag(localname, attrsD.items()) + self.unknown_starttag(localname, list(attrsD.items())) def characters(self, text): self.handle_data(text) @@ -1436,7 +1437,7 @@ class _BaseHTMLProcessor(sgmllib.SGMLParser): data = re.sub(r'<([^<\s]+?)\s*/>', self._shorttag_replace, data) data = data.replace(''', "'") data = data.replace('"', '"') - if self.encoding and type(data) == type(u''): + if self.encoding and type(data) == type(''): data = data.encode(self.encoding) sgmllib.SGMLParser.feed(self, data) @@ -1454,10 +1455,10 @@ class _BaseHTMLProcessor(sgmllib.SGMLParser): uattrs = [] # thanks to Kevin Marks for this breathtaking hack to deal with (valid) high-bit attribute values in UTF-8 feeds for key, value in attrs: - if type(value) != type(u''): - value = unicode(value, self.encoding) - uattrs.append((unicode(key, self.encoding), value)) - strattrs = u''.join([u' %s="%s"' % (key, value) for key, value in uattrs]).encode(self.encoding) + if type(value) != type(''): + value = str(value, self.encoding) + uattrs.append((str(key, self.encoding), value)) + strattrs = ''.join([' %s="%s"' % (key, value) for key, value in uattrs]).encode(self.encoding) if tag in self.elements_no_end_tag: self.pieces.append('<%(tag)s%(strattrs)s />' % locals()) else: @@ -1541,7 +1542,7 @@ class _LooseFeedParser(_FeedParserMixin, _BaseHTMLProcessor): data = data.replace('"', '"') data = data.replace(''', ''') data = data.replace(''', ''') - if self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'): + if 'type' in self.contentparams and not self.contentparams.get('type', 'xml').endswith('xml'): data = data.replace('<', '<') data = data.replace('>', '>') data = data.replace('&', '&') @@ -1671,12 +1672,12 @@ def _sanitizeHTML(htmlSource, encoding): except: pass if _tidy: - utf8 = type(data) == type(u'') + utf8 = type(data) == type('') if utf8: data = data.encode('utf-8') data = _tidy(data, output_xhtml=1, numeric_entities=1, wrap=0, char_encoding="utf8") if utf8: - data = unicode(data, 'utf-8') + data = str(data, 'utf-8') if data.count(''): @@ -1686,7 +1687,7 @@ def _sanitizeHTML(htmlSource, encoding): data = data.strip().replace('\r\n', '\n') return data -class _FeedURLHandler(urllib2.HTTPDigestAuthHandler, urllib2.HTTPRedirectHandler, urllib2.HTTPDefaultErrorHandler): +class _FeedURLHandler(urllib.request.HTTPDigestAuthHandler, urllib.request.HTTPRedirectHandler, urllib.request.HTTPDefaultErrorHandler): def http_error_default(self, req, fp, code, msg, headers): if ((code / 100) == 3) and (code != 304): return self.http_error_302(req, fp, code, msg, headers) @@ -1695,8 +1696,8 @@ class _FeedURLHandler(urllib2.HTTPDigestAuthHandler, urllib2.HTTPRedirectHandler return infourl def http_error_302(self, req, fp, code, msg, headers): - if headers.dict.has_key('location'): - infourl = urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers) + if 'location' in headers.dict: + infourl = urllib.request.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers) else: infourl = urllib.addinfourl(fp, headers, req.get_full_url()) if not hasattr(infourl, 'status'): @@ -1704,8 +1705,8 @@ class _FeedURLHandler(urllib2.HTTPDigestAuthHandler, urllib2.HTTPRedirectHandler return infourl def http_error_301(self, req, fp, code, msg, headers): - if headers.dict.has_key('location'): - infourl = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers) + if 'location' in headers.dict: + infourl = urllib.request.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers) else: infourl = urllib.addinfourl(fp, headers, req.get_full_url()) if not hasattr(infourl, 'status'): @@ -1727,7 +1728,7 @@ class _FeedURLHandler(urllib2.HTTPDigestAuthHandler, urllib2.HTTPRedirectHandler # header the server sent back (for the realm) and retry # the request with the appropriate digest auth headers instead. # This evil genius hack has been brought to you by Aaron Swartz. - host = urlparse.urlparse(req.get_full_url())[1] + host = urllib.parse.urlparse(req.get_full_url())[1] try: assert sys.version.split()[0] >= '2.3.3' assert base64 != None @@ -1773,21 +1774,21 @@ def _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, h if url_file_stream_or_string == '-': return sys.stdin - if urlparse.urlparse(url_file_stream_or_string)[0] in ('http', 'https', 'ftp'): + if urllib.parse.urlparse(url_file_stream_or_string)[0] in ('http', 'https', 'ftp'): if not agent: agent = USER_AGENT # test for inline user:password for basic auth auth = None if base64: - urltype, rest = urllib.splittype(url_file_stream_or_string) - realhost, rest = urllib.splithost(rest) + urltype, rest = urllib.parse.splittype(url_file_stream_or_string) + realhost, rest = urllib.parse.splithost(rest) if realhost: - user_passwd, realhost = urllib.splituser(realhost) + user_passwd, realhost = urllib.parse.splituser(realhost) if user_passwd: url_file_stream_or_string = '%s://%s%s' % (urltype, realhost, rest) auth = base64.encodestring(user_passwd).strip() # try to open with urllib2 (to use optional headers) - request = urllib2.Request(url_file_stream_or_string) + request = urllib.request.Request(url_file_stream_or_string) request.add_header('User-Agent', agent) if etag: request.add_header('If-None-Match', etag) @@ -1814,7 +1815,7 @@ def _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, h if ACCEPT_HEADER: request.add_header('Accept', ACCEPT_HEADER) request.add_header('A-IM', 'feed') # RFC 3229 support - opener = apply(urllib2.build_opener, tuple([_FeedURLHandler()] + handlers)) + opener = urllib.request.build_opener(*tuple([_FeedURLHandler()] + handlers)) opener.addheaders = [] # RMK - must clear so we only send our custom User-Agent try: return opener.open(request) @@ -1910,7 +1911,7 @@ def _parse_date_iso8601(dateString): day = int(day) # special case of the century - is the first year of the 21st century # 2000 or 2001 ? The debate goes on... - if 'century' in params.keys(): + if 'century' in list(params.keys()): year = (int(params['century']) - 1) * 100 + 1 # in ISO 8601 most fields are optional for field in ['hour', 'minute', 'second', 'tzhour', 'tzmin']: @@ -1946,17 +1947,17 @@ def _parse_date_iso8601(dateString): registerDateHandler(_parse_date_iso8601) # 8-bit date handling routines written by ytrewq1. -_korean_year = u'\ub144' # b3e2 in euc-kr -_korean_month = u'\uc6d4' # bff9 in euc-kr -_korean_day = u'\uc77c' # c0cf in euc-kr -_korean_am = u'\uc624\uc804' # bfc0 c0fc in euc-kr -_korean_pm = u'\uc624\ud6c4' # bfc0 c8c4 in euc-kr +_korean_year = '\ub144' # b3e2 in euc-kr +_korean_month = '\uc6d4' # bff9 in euc-kr +_korean_day = '\uc77c' # c0cf in euc-kr +_korean_am = '\uc624\uc804' # bfc0 c0fc in euc-kr +_korean_pm = '\uc624\ud6c4' # bfc0 c8c4 in euc-kr _korean_onblog_date_re = \ re.compile('(\d{4})%s\s+(\d{2})%s\s+(\d{2})%s\s+(\d{2}):(\d{2}):(\d{2})' % \ (_korean_year, _korean_month, _korean_day)) _korean_nate_date_re = \ - re.compile(u'(\d{4})-(\d{2})-(\d{2})\s+(%s|%s)\s+(\d{,2}):(\d{,2}):(\d{,2})' % \ + re.compile('(\d{4})-(\d{2})-(\d{2})\s+(%s|%s)\s+(\d{,2}):(\d{,2}):(\d{,2})' % \ (_korean_am, _korean_pm)) def _parse_date_onblog(dateString): '''Parse a string according to the OnBlog 8-bit date format''' @@ -2006,40 +2007,40 @@ registerDateHandler(_parse_date_mssql) # Unicode strings for Greek date strings _greek_months = \ { \ - u'\u0399\u03b1\u03bd': u'Jan', # c9e1ed in iso-8859-7 - u'\u03a6\u03b5\u03b2': u'Feb', # d6e5e2 in iso-8859-7 - u'\u039c\u03ac\u03ce': u'Mar', # ccdcfe in iso-8859-7 - u'\u039c\u03b1\u03ce': u'Mar', # cce1fe in iso-8859-7 - u'\u0391\u03c0\u03c1': u'Apr', # c1f0f1 in iso-8859-7 - u'\u039c\u03ac\u03b9': u'May', # ccdce9 in iso-8859-7 - u'\u039c\u03b1\u03ca': u'May', # cce1fa in iso-8859-7 - u'\u039c\u03b1\u03b9': u'May', # cce1e9 in iso-8859-7 - u'\u0399\u03bf\u03cd\u03bd': u'Jun', # c9effded in iso-8859-7 - u'\u0399\u03bf\u03bd': u'Jun', # c9efed in iso-8859-7 - u'\u0399\u03bf\u03cd\u03bb': u'Jul', # c9effdeb in iso-8859-7 - u'\u0399\u03bf\u03bb': u'Jul', # c9f9eb in iso-8859-7 - u'\u0391\u03cd\u03b3': u'Aug', # c1fde3 in iso-8859-7 - u'\u0391\u03c5\u03b3': u'Aug', # c1f5e3 in iso-8859-7 - u'\u03a3\u03b5\u03c0': u'Sep', # d3e5f0 in iso-8859-7 - u'\u039f\u03ba\u03c4': u'Oct', # cfeaf4 in iso-8859-7 - u'\u039d\u03bf\u03ad': u'Nov', # cdefdd in iso-8859-7 - u'\u039d\u03bf\u03b5': u'Nov', # cdefe5 in iso-8859-7 - u'\u0394\u03b5\u03ba': u'Dec', # c4e5ea in iso-8859-7 + '\u0399\u03b1\u03bd': 'Jan', # c9e1ed in iso-8859-7 + '\u03a6\u03b5\u03b2': 'Feb', # d6e5e2 in iso-8859-7 + '\u039c\u03ac\u03ce': 'Mar', # ccdcfe in iso-8859-7 + '\u039c\u03b1\u03ce': 'Mar', # cce1fe in iso-8859-7 + '\u0391\u03c0\u03c1': 'Apr', # c1f0f1 in iso-8859-7 + '\u039c\u03ac\u03b9': 'May', # ccdce9 in iso-8859-7 + '\u039c\u03b1\u03ca': 'May', # cce1fa in iso-8859-7 + '\u039c\u03b1\u03b9': 'May', # cce1e9 in iso-8859-7 + '\u0399\u03bf\u03cd\u03bd': 'Jun', # c9effded in iso-8859-7 + '\u0399\u03bf\u03bd': 'Jun', # c9efed in iso-8859-7 + '\u0399\u03bf\u03cd\u03bb': 'Jul', # c9effdeb in iso-8859-7 + '\u0399\u03bf\u03bb': 'Jul', # c9f9eb in iso-8859-7 + '\u0391\u03cd\u03b3': 'Aug', # c1fde3 in iso-8859-7 + '\u0391\u03c5\u03b3': 'Aug', # c1f5e3 in iso-8859-7 + '\u03a3\u03b5\u03c0': 'Sep', # d3e5f0 in iso-8859-7 + '\u039f\u03ba\u03c4': 'Oct', # cfeaf4 in iso-8859-7 + '\u039d\u03bf\u03ad': 'Nov', # cdefdd in iso-8859-7 + '\u039d\u03bf\u03b5': 'Nov', # cdefe5 in iso-8859-7 + '\u0394\u03b5\u03ba': 'Dec', # c4e5ea in iso-8859-7 } _greek_wdays = \ { \ - u'\u039a\u03c5\u03c1': u'Sun', # caf5f1 in iso-8859-7 - u'\u0394\u03b5\u03c5': u'Mon', # c4e5f5 in iso-8859-7 - u'\u03a4\u03c1\u03b9': u'Tue', # d4f1e9 in iso-8859-7 - u'\u03a4\u03b5\u03c4': u'Wed', # d4e5f4 in iso-8859-7 - u'\u03a0\u03b5\u03bc': u'Thu', # d0e5ec in iso-8859-7 - u'\u03a0\u03b1\u03c1': u'Fri', # d0e1f1 in iso-8859-7 - u'\u03a3\u03b1\u03b2': u'Sat', # d3e1e2 in iso-8859-7 + '\u039a\u03c5\u03c1': 'Sun', # caf5f1 in iso-8859-7 + '\u0394\u03b5\u03c5': 'Mon', # c4e5f5 in iso-8859-7 + '\u03a4\u03c1\u03b9': 'Tue', # d4f1e9 in iso-8859-7 + '\u03a4\u03b5\u03c4': 'Wed', # d4e5f4 in iso-8859-7 + '\u03a0\u03b5\u03bc': 'Thu', # d0e5ec in iso-8859-7 + '\u03a0\u03b1\u03c1': 'Fri', # d0e1f1 in iso-8859-7 + '\u03a3\u03b1\u03b2': 'Sat', # d3e1e2 in iso-8859-7 } _greek_date_format_re = \ - re.compile(u'([^,]+),\s+(\d{2})\s+([^\s]+)\s+(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s+([^\s]+)') + re.compile('([^,]+),\s+(\d{2})\s+([^\s]+)\s+(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s+([^\s]+)') def _parse_date_greek(dateString): '''Parse a string according to a Greek 8-bit date format.''' @@ -2061,22 +2062,22 @@ registerDateHandler(_parse_date_greek) # Unicode strings for Hungarian date strings _hungarian_months = \ { \ - u'janu\u00e1r': u'01', # e1 in iso-8859-2 - u'febru\u00e1ri': u'02', # e1 in iso-8859-2 - u'm\u00e1rcius': u'03', # e1 in iso-8859-2 - u'\u00e1prilis': u'04', # e1 in iso-8859-2 - u'm\u00e1ujus': u'05', # e1 in iso-8859-2 - u'j\u00fanius': u'06', # fa in iso-8859-2 - u'j\u00falius': u'07', # fa in iso-8859-2 - u'augusztus': u'08', - u'szeptember': u'09', - u'okt\u00f3ber': u'10', # f3 in iso-8859-2 - u'november': u'11', - u'december': u'12', + 'janu\u00e1r': '01', # e1 in iso-8859-2 + 'febru\u00e1ri': '02', # e1 in iso-8859-2 + 'm\u00e1rcius': '03', # e1 in iso-8859-2 + '\u00e1prilis': '04', # e1 in iso-8859-2 + 'm\u00e1ujus': '05', # e1 in iso-8859-2 + 'j\u00fanius': '06', # fa in iso-8859-2 + 'j\u00falius': '07', # fa in iso-8859-2 + 'augusztus': '08', + 'szeptember': '09', + 'okt\u00f3ber': '10', # f3 in iso-8859-2 + 'november': '11', + 'december': '12', } _hungarian_date_format_re = \ - re.compile(u'(\d{4})-([^-]+)-(\d{,2})T(\d{,2}):(\d{2})((\+|-)(\d{,2}:\d{2}))') + re.compile('(\d{4})-([^-]+)-(\d{,2})T(\d{,2}):(\d{2})((\+|-)(\d{,2}:\d{2}))') def _parse_date_hungarian(dateString): '''Parse a string according to a Hungarian 8-bit date format.''' @@ -2232,7 +2233,7 @@ def _parse_date(dateString): if len(date9tuple) != 9: if _debug: sys.stderr.write('date handler function must return 9-tuple\n') raise ValueError - map(int, date9tuple) + list(map(int, date9tuple)) return date9tuple except Exception as e: if _debug: sys.stderr.write('%s raised %s\n' % (handler.__name__, repr(e))) @@ -2313,39 +2314,39 @@ def _getCharacterEncoding(http_headers, xml_data): elif xml_data[:4] == '\x00\x3c\x00\x3f': # UTF-16BE sniffed_xml_encoding = 'utf-16be' - xml_data = unicode(xml_data, 'utf-16be').encode('utf-8') + xml_data = str(xml_data, 'utf-16be').encode('utf-8') elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') and (xml_data[2:4] != '\x00\x00'): # UTF-16BE with BOM sniffed_xml_encoding = 'utf-16be' - xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8') + xml_data = str(xml_data[2:], 'utf-16be').encode('utf-8') elif xml_data[:4] == '\x3c\x00\x3f\x00': # UTF-16LE sniffed_xml_encoding = 'utf-16le' - xml_data = unicode(xml_data, 'utf-16le').encode('utf-8') + xml_data = str(xml_data, 'utf-16le').encode('utf-8') elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and (xml_data[2:4] != '\x00\x00'): # UTF-16LE with BOM sniffed_xml_encoding = 'utf-16le' - xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8') + xml_data = str(xml_data[2:], 'utf-16le').encode('utf-8') elif xml_data[:4] == '\x00\x00\x00\x3c': # UTF-32BE sniffed_xml_encoding = 'utf-32be' - xml_data = unicode(xml_data, 'utf-32be').encode('utf-8') + xml_data = str(xml_data, 'utf-32be').encode('utf-8') elif xml_data[:4] == '\x3c\x00\x00\x00': # UTF-32LE sniffed_xml_encoding = 'utf-32le' - xml_data = unicode(xml_data, 'utf-32le').encode('utf-8') + xml_data = str(xml_data, 'utf-32le').encode('utf-8') elif xml_data[:4] == '\x00\x00\xfe\xff': # UTF-32BE with BOM sniffed_xml_encoding = 'utf-32be' - xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8') + xml_data = str(xml_data[4:], 'utf-32be').encode('utf-8') elif xml_data[:4] == '\xff\xfe\x00\x00': # UTF-32LE with BOM sniffed_xml_encoding = 'utf-32le' - xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8') + xml_data = str(xml_data[4:], 'utf-32le').encode('utf-8') elif xml_data[:3] == '\xef\xbb\xbf': # UTF-8 with BOM sniffed_xml_encoding = 'utf-8' - xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8') + xml_data = str(xml_data[3:], 'utf-8').encode('utf-8') else: # ASCII-compatible pass @@ -2369,7 +2370,7 @@ def _getCharacterEncoding(http_headers, xml_data): true_encoding = http_encoding or 'us-ascii' elif http_content_type.startswith('text/'): true_encoding = http_encoding or 'us-ascii' - elif http_headers and (not http_headers.has_key('content-type')): + elif http_headers and ('content-type' not in http_headers): true_encoding = xml_encoding or 'iso-8859-1' else: true_encoding = xml_encoding or 'utf-8' @@ -2418,14 +2419,14 @@ def _toUTF8(data, encoding): sys.stderr.write('trying utf-32le instead\n') encoding = 'utf-32le' data = data[4:] - newdata = unicode(data, encoding) + newdata = str(data, encoding) if _debug: sys.stderr.write('successfully converted %s data to unicode\n' % encoding) declmatch = re.compile('^<\?xml[^>]*?>') newdecl = '''''' if declmatch.search(newdata): newdata = declmatch.sub(newdecl, newdata) else: - newdata = newdecl + u'\n' + newdata + newdata = newdecl + '\n' + newdata return newdata.encode('utf-8') def _stripDoctype(data): @@ -2511,7 +2512,7 @@ def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, refer result['encoding'], http_encoding, xml_encoding, sniffed_xml_encoding, acceptable_content_type = \ _getCharacterEncoding(http_headers, data) if http_headers and (not acceptable_content_type): - if http_headers.has_key('content-type'): + if 'content-type' in http_headers: bozo_message = '%s is not an XML media type' % http_headers['content-type'] else: bozo_message = 'no Content-type specified' @@ -2629,18 +2630,18 @@ def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, refer if __name__ == '__main__': if not sys.argv[1:]: - print __doc__ + print(__doc__) sys.exit(0) else: urls = sys.argv[1:] zopeCompatibilityHack() from pprint import pprint for url in urls: - print url - print + print(url) + print() result = parse(url) pprint(result) - print + print() #REVISION HISTORY #1.0 - 9/27/2002 - MAP - fixed namespace processing on prefixed RSS 2.0 elements, diff --git a/libs/pytwmn.py b/libs/pytwmn.py index 49661fb..6b2d774 100644 --- a/libs/pytwmn.py +++ b/libs/pytwmn.py @@ -45,8 +45,8 @@ def init(host="127.0.0.1", port=None): class Notification(object): def __init__(self, title="", msg="", icon=""): - self.title = unicode(title) - self.msg = unicode(msg) + self.title = str(title) + self.msg = str(msg) if icon.startswith("file://"): icon = icon[7:] self.icon = icon diff --git a/logviewer.py b/logviewer.py index 779781c..3c0b21e 100644 --- a/logviewer.py +++ b/logviewer.py @@ -3,19 +3,19 @@ import codecs import re import ostools from time import strftime, strptime -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets from generic import RightClickList, RightClickTree from parsetools import convertTags from convo import PesterText _datadir = ostools.getDataDir() -class PesterLogSearchInput(QtGui.QLineEdit): +class PesterLogSearchInput(QtWidgets.QLineEdit): def __init__(self, theme, parent=None): - QtGui.QLineEdit.__init__(self, parent) + QtWidgets.QLineEdit.__init__(self, parent) self.setStyleSheet(theme["convo/input/style"] + "margin-right:0px;") def keyPressEvent(self, event): - QtGui.QLineEdit.keyPressEvent(self, event) + QtWidgets.QLineEdit.keyPressEvent(self, event) if hasattr(self.parent(), 'textArea'): if event.key() == QtCore.Qt.Key_Return: self.parent().logSearch(self.text()) @@ -33,12 +33,12 @@ class PesterLogHighlighter(QtGui.QSyntaxHighlighter): self.hilightstyle.setForeground(QtGui.QBrush(QtCore.Qt.black)) def highlightBlock(self, text): for i in range(0, len(text)-(len(self.searchTerm)-1)): - if unicode(text[i:i+len(self.searchTerm)]).lower() == unicode(self.searchTerm).lower(): + if str(text[i:i+len(self.searchTerm)]).lower() == str(self.searchTerm).lower(): self.setFormat(i, len(self.searchTerm), self.hilightstyle) -class PesterLogUserSelect(QtGui.QDialog): +class PesterLogUserSelect(QtWidgets.QDialog): def __init__(self, config, theme, parent): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.setModal(False) self.config = config self.theme = theme @@ -49,7 +49,7 @@ class PesterLogUserSelect(QtGui.QDialog): self.setStyleSheet(self.theme["main/defaultwindow/style"]) self.setWindowTitle("Pesterlogs") - instructions = QtGui.QLabel("Pick a memo or chumhandle:") + instructions = QtWidgets.QLabel("Pick a memo or chumhandle:") if os.path.exists("%s/%s" % (self.logpath, self.handle)): chumMemoList = os.listdir("%s/%s/" % (self.logpath, self.handle)) @@ -63,31 +63,28 @@ class PesterLogUserSelect(QtGui.QDialog): self.chumsBox = RightClickList(self) self.chumsBox.setStyleSheet(self.theme["main/chums/style"]) - self.chumsBox.optionsMenu = QtGui.QMenu(self) + self.chumsBox.optionsMenu = QtWidgets.QMenu(self) for (i, t) in enumerate(chumMemoList): - item = QtGui.QListWidgetItem(t) + item = QtWidgets.QListWidgetItem(t) item.setTextColor(QtGui.QColor(self.theme["main/chums/userlistcolor"])) self.chumsBox.addItem(item) self.search = PesterLogSearchInput(theme, self) self.search.setFocus() - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - self.ok = QtGui.QPushButton("OK", self) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('viewActivatedLog()')) - layout_ok = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.viewActivatedLog) + layout_ok = QtWidgets.QHBoxLayout() layout_ok.addWidget(self.cancel) layout_ok.addWidget(self.ok) - self.directory = QtGui.QPushButton("LOG DIRECTORY", self) - self.connect(self.directory, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('openDir()')) + self.directory = QtWidgets.QPushButton("LOG DIRECTORY", self) + self.directory.clicked.connect(self.openDir) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(instructions) layout_0.addWidget(self.chumsBox) layout_0.addWidget(self.search) @@ -111,8 +108,7 @@ class PesterLogUserSelect(QtGui.QDialog): self.pesterlogviewer = None if not self.pesterlogviewer: self.pesterlogviewer = PesterLogViewer(selectedchum, self.config, self.theme, self.parent) - self.connect(self.pesterlogviewer, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('closeActiveLog()')) + self.pesterlogviewer.rejected.connect(self.closeActiveLog) self.pesterlogviewer.show() self.pesterlogviewer.raise_() self.pesterlogviewer.activateWindow() @@ -127,9 +123,9 @@ class PesterLogUserSelect(QtGui.QDialog): def openDir(self): QtGui.QDesktopServices.openUrl(QtCore.QUrl("file:///" + os.path.join(_datadir, "logs"), QtCore.QUrl.TolerantMode)) -class PesterLogViewer(QtGui.QDialog): +class PesterLogViewer(QtWidgets.QDialog): def __init__(self, chum, config, theme, parent): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.setModal(False) self.config = config self.theme = theme @@ -151,27 +147,26 @@ class PesterLogViewer(QtGui.QDialog): self.logList = [] if not os.path.exists("%s/%s/%s/%s" % (self.logpath, self.handle, chum, self.format)) or len(self.logList) == 0: - instructions = QtGui.QLabel("No Pesterlogs were found") + instructions = QtWidgets.QLabel("No Pesterlogs were found") - self.ok = QtGui.QPushButton("CLOSE", self) + self.ok = QtWidgets.QPushButton("CLOSE", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_ok = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.reject) + layout_ok = QtWidgets.QHBoxLayout() layout_ok.addWidget(self.ok) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(instructions) layout_0.addLayout(layout_ok) self.setLayout(layout_0) else: - self.instructions = QtGui.QLabel("Pesterlog with " +self.chum+ " on") + self.instructions = QtWidgets.QLabel("Pesterlog with " +self.chum+ " on") self.textArea = PesterLogText(theme, self.parent) self.textArea.setReadOnly(True) self.textArea.setFixedWidth(600) - if theme.has_key("convo/scrollbar"): + if "convo/scrollbar" in theme: self.textArea.setStyleSheet("QTextEdit { width:500px; %s } QScrollBar:vertical { %s } QScrollBar::handle:vertical { %s } QScrollBar::add-line:vertical { %s } QScrollBar::sub-line:vertical { %s } QScrollBar:up-arrow:vertical { %s } QScrollBar:down-arrow:vertical { %s }" % (theme["convo/textarea/style"], theme["convo/scrollbar/style"], theme["convo/scrollbar/handle"], theme["convo/scrollbar/downarrow"], theme["convo/scrollbar/uparrow"], theme["convo/scrollbar/uarrowstyle"], theme["convo/scrollbar/darrowstyle"] )) else: self.textArea.setStyleSheet("QTextEdit { width:500px; %s }" % (theme["convo/textarea/style"])) @@ -180,15 +175,14 @@ class PesterLogViewer(QtGui.QDialog): self.logList.reverse() self.tree = RightClickTree() - self.tree.optionsMenu = QtGui.QMenu(self) + self.tree.optionsMenu = QtWidgets.QMenu(self) self.tree.setFixedSize(260, 300) self.tree.header().hide() - if theme.has_key("convo/scrollbar"): + if "convo/scrollbar" in theme: self.tree.setStyleSheet("QTreeWidget { %s } QScrollBar:vertical { %s } QScrollBar::handle:vertical { %s } QScrollBar::add-line:vertical { %s } QScrollBar::sub-line:vertical { %s } QScrollBar:up-arrow:vertical { %s } QScrollBar:down-arrow:vertical { %s }" % (theme["convo/textarea/style"], theme["convo/scrollbar/style"], theme["convo/scrollbar/handle"], theme["convo/scrollbar/downarrow"], theme["convo/scrollbar/uparrow"], theme["convo/scrollbar/uarrowstyle"], theme["convo/scrollbar/darrowstyle"] )) else: self.tree.setStyleSheet("%s" % (theme["convo/textarea/style"])) - self.connect(self.tree, QtCore.SIGNAL('itemSelectionChanged()'), - self, QtCore.SLOT('loadSelectedLog()')) + self.tree.itemSelectionChanged.connect(self.loadSelectedLog) self.tree.setSortingEnabled(False) child_1 = None @@ -196,11 +190,11 @@ class PesterLogViewer(QtGui.QDialog): for (i,l) in enumerate(self.logList): my = self.fileToMonthYear(l) if my[0] != last[0]: - child_1 = QtGui.QTreeWidgetItem(["%s %s" % (my[0], my[1])]) + child_1 = QtWidgets.QTreeWidgetItem(["%s %s" % (my[0], my[1])]) self.tree.addTopLevelItem(child_1) if i == 0: child_1.setExpanded(True) - child_1.addChild(QtGui.QTreeWidgetItem([self.fileToTime(l)])) + child_1.addChild(QtWidgets.QTreeWidgetItem([self.fileToTime(l)])) last = self.fileToMonthYear(l) self.hilight = PesterLogHighlighter(self.textArea) @@ -208,38 +202,36 @@ class PesterLogViewer(QtGui.QDialog): self.search = PesterLogSearchInput(theme, self) self.search.setFocus() - self.find = QtGui.QPushButton("Find", self) + self.find = QtWidgets.QPushButton("Find", self) font = self.find.font() font.setPointSize(8) self.find.setFont(font) self.find.setDefault(True) self.find.setFixedSize(40, 20) - layout_search = QtGui.QHBoxLayout() + layout_search = QtWidgets.QHBoxLayout() layout_search.addWidget(self.search) layout_search.addWidget(self.find) - self.qdb = QtGui.QPushButton("Pesterchum QDB", self) + self.qdb = QtWidgets.QPushButton("Pesterchum QDB", self) self.qdb.setFixedWidth(260) - self.connect(self.qdb, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('openQDB()')) - self.ok = QtGui.QPushButton("CLOSE", self) + self.qdb.clicked.connect(self.openQDB) + self.ok = QtWidgets.QPushButton("CLOSE", self) self.ok.setFixedWidth(80) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_ok = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.reject) + layout_ok = QtWidgets.QHBoxLayout() # Website is offline so there's no point. #layout_ok.addWidget(self.qdb) layout_ok.addWidget(self.ok) layout_ok.setAlignment(self.ok, QtCore.Qt.AlignRight) - layout_logs = QtGui.QHBoxLayout() + layout_logs = QtWidgets.QHBoxLayout() layout_logs.addWidget(self.tree) - layout_right = QtGui.QVBoxLayout() + layout_right = QtWidgets.QVBoxLayout() layout_right.addWidget(self.textArea) layout_right.addLayout(layout_search) layout_logs.addLayout(layout_right) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.instructions) layout_0.addLayout(layout_logs) layout_0.addLayout(layout_ok) @@ -265,7 +257,7 @@ class PesterLogViewer(QtGui.QDialog): textCur = self.textArea.textCursor() textCur.movePosition(1) self.textArea.setTextCursor(textCur) - self.instructions.setText("Pesterlog with " +self.chum+ " on " + self.fileToTime(unicode(fname))) + self.instructions.setText("Pesterlog with " +self.chum+ " on " + self.fileToTime(str(fname))) def logSearch(self, search): self.hilight.searchTerm = search @@ -285,20 +277,20 @@ class PesterLogText(PesterText): PesterText.__init__(self, theme, parent) def focusInEvent(self, event): - QtGui.QTextEdit.focusInEvent(self, event) + QtWidgets.QTextEdit.focusInEvent(self, event) def mousePressEvent(self, event): url = self.anchorAt(event.pos()) if url != "": if url[0] == "#" and url != "#pesterchum": self.parent().parent.showMemos(url[1:]) elif url[0] == "@": - handle = unicode(url[1:]) + handle = str(url[1:]) self.parent().parent.newConversation(handle) else: QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode)) - QtGui.QTextEdit.mousePressEvent(self, event) + QtWidgets.QTextEdit.mousePressEvent(self, event) def mouseMoveEvent(self, event): - QtGui.QTextEdit.mouseMoveEvent(self, event) + QtWidgets.QTextEdit.mouseMoveEvent(self, event) if self.anchorAt(event.pos()): if self.viewport().cursor().shape != QtCore.Qt.PointingHandCursor: self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) diff --git a/luaquirks.py b/luaquirks.py index b81e386..59319fc 100644 --- a/luaquirks.py +++ b/luaquirks.py @@ -4,7 +4,7 @@ try: except ImportError: lua = None from quirks import ScriptQuirks -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets class LuaQuirks(ScriptQuirks): def loadModule(self, name, filename): @@ -18,7 +18,7 @@ class LuaQuirks(ScriptQuirks): try: return lua.require(name) except Error as e: - print e + print(e) return None finally: os.chdir(CurrentDir) @@ -48,11 +48,11 @@ class LuaQuirks(ScriptQuirks): for name in module.commands: CommandWrapper = Wrapper(module,name) try: - if not isinstance(CommandWrapper("test"), basestring): + if not isinstance(CommandWrapper("test"), str): raise Exception except: - print "Quirk malformed: %s" % (name) - msgbox = QtGui.QMessageBox() + print("Quirk malformed: %s" % (name)) + msgbox = QtWidgets.QMessageBox() msgbox.setWindowTitle("Error!") msgbox.setText("Quirk malformed: %s" % (name)) msgbox.exec_() diff --git a/memos.py b/memos.py index 88d704d..9b6e69d 100644 --- a/memos.py +++ b/memos.py @@ -1,7 +1,7 @@ from string import Template import re from copy import copy -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets from datetime import time, timedelta, datetime from mood import Mood @@ -13,6 +13,12 @@ from parsetools import convertTags, addTimeInitial, timeProtocol, \ import parsetools from logviewer import PesterLogViewer +try: + QString = unicode +except NameError: + # Python 3 + QString = str + def delta2txt(d, format="pc"): if type(d) is mysteryTime: return "?" @@ -153,7 +159,7 @@ class TimeTracker(list): except ValueError: return None def openTime(self, time): - if self.open.has_key(time): + if time in self.open: self.open[time] = True def openCurrentTime(self): timed = self.getTime() @@ -179,21 +185,19 @@ class TimeTracker(list): return TimeGrammar(temporal, pcf, when, 0) return TimeGrammar(temporal, pcf, when, self.getRecord(timed)) -class TimeInput(QtGui.QLineEdit): +class TimeInput(QtWidgets.QLineEdit): def __init__(self, timeslider, parent): super(TimeInput, self).__init__(parent) self.timeslider = timeslider self.setText("+0:00") - self.connect(self.timeslider, QtCore.SIGNAL('valueChanged(int)'), - self, QtCore.SLOT('setTime(int)')) - self.connect(self, QtCore.SIGNAL('editingFinished()'), - self, QtCore.SLOT('setSlider()')) + self.timeslider.valueChanged[int].connect(self.setTime) + self.editingFinished.connect(self.setSlider) @QtCore.pyqtSlot(int) def setTime(self, sliderval): self.setText(self.timeslider.getTime()) @QtCore.pyqtSlot() def setSlider(self): - value = unicode(self.text()) + value = str(self.text()) timed = txt2delta(value) if type(timed) is mysteryTime: self.timeslider.setValue(0) @@ -210,7 +214,7 @@ class TimeInput(QtGui.QLineEdit): text = delta2txt(timed) self.setText(text) -class TimeSlider(QtGui.QSlider): +class TimeSlider(QtWidgets.QSlider): def __init__(self, orientation, parent): super(TimeSlider, self).__init__(orientation, parent) self.setTracking(True) @@ -258,22 +262,20 @@ class MemoText(PesterText): self.setReadOnly(True) self.setMouseTracking(True) self.textSelected = False - self.connect(self, QtCore.SIGNAL('copyAvailable(bool)'), - self, QtCore.SLOT('textReady(bool)')) + self.copyAvailable[bool].connect(self.textReady) self.urls = {} for k in smiledict: self.addAnimation(QtCore.QUrl("smilies/%s" % (smiledict[k])), "smilies/%s" % (smiledict[k])) - self.connect(self.mainwindow, QtCore.SIGNAL('animationSetting(bool)'), - self, QtCore.SLOT('animateChanged(bool)')) + self.mainwindow.animationSetting[bool].connect(self.animateChanged) def initTheme(self, theme): - if theme.has_key("memos/scrollbar"): + if "memos/scrollbar" in theme: self.setStyleSheet("QTextEdit { %s } QScrollBar:vertical { %s } QScrollBar::handle:vertical { %s } QScrollBar::add-line:vertical { %s } QScrollBar::sub-line:vertical { %s } QScrollBar:up-arrow:vertical { %s } QScrollBar:down-arrow:vertical { %s }" % (theme["memos/textarea/style"], theme["memos/scrollbar/style"], theme["memos/scrollbar/handle"], theme["memos/scrollbar/downarrow"], theme["memos/scrollbar/uparrow"], theme["memos/scrollbar/uarrowstyle"], theme["memos/scrollbar/darrowstyle"] )) else: self.setStyleSheet("QTextEdit { %s }" % theme["memos/textarea/style"]) def addMessage(self, msg, chum): - if type(msg) in [str, unicode]: + if type(msg) in [str, str]: lexmsg = lexMessage(msg) else: lexmsg = msg @@ -304,7 +306,7 @@ class MemoText(PesterText): chum.color = color systemColor = QtGui.QColor(window.theme["memos/systemMsgColor"]) if chum is not me: - if parent.times.has_key(chum.handle): + if chum.handle in parent.times: time = parent.times[chum.handle] if time.getTime() is None: # MY WAY OR THE HIGHWAY @@ -352,81 +354,67 @@ class MemoInput(PesterInput): class PesterMemo(PesterConvo): # TODO: Clean up inheritance between these!! The inits are ugly. def __init__(self, channel, timestr, mainwindow, parent=None): - QtGui.QFrame.__init__(self, parent) + QtWidgets.QFrame.__init__(self, parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.channel = channel self.setObjectName(self.channel) self.mainwindow = mainwindow self.time = TimeTracker(txt2delta(timestr)) self.setWindowTitle(channel) - self.channelLabel = QtGui.QLabel(self) - self.channelLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)) + self.channelLabel = QtWidgets.QLabel(self) + self.channelLabel.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)) self.textArea = MemoText(self.mainwindow.theme, self) self.textInput = MemoInput(self.mainwindow.theme, self) self.textInput.setFocus() - self.miniUserlist = QtGui.QPushButton(">\n>", self) + self.miniUserlist = QtWidgets.QPushButton(">\n>", self) #self.miniUserlist.setStyleSheet("border:1px solid #a68168; border-width: 2px 0px 2px 2px; height: 90px; width: 10px; color: #cd8f9d; font-family: 'Arial'; background: white; margin-left: 2px;") - self.connect(self.miniUserlist, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('toggleUserlist()')) + self.miniUserlist.clicked.connect(self.toggleUserlist) self.userlist = RightClickList(self) - self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding)) - self.userlist.optionsMenu = QtGui.QMenu(self) - self.pesterChumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self) - self.connect(self.pesterChumAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('newPesterSlot()')) - self.addchumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self) - self.connect(self.addchumAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('addChumSlot()')) - self.banuserAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/banuser"], self) - self.connect(self.banuserAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('banSelectedUser()')) - self.opAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/opuser"], self) - self.connect(self.opAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('opSelectedUser()')) - self.voiceAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/voiceuser"], self) - self.connect(self.voiceAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('voiceSelectedUser()')) - self.quirkDisableAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirkkill"], self) - self.connect(self.quirkDisableAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('killQuirkUser()')) + self.userlist.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding)) + self.userlist.optionsMenu = QtWidgets.QMenu(self) + self.pesterChumAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self) + self.pesterChumAction.triggered.connect(self.newPesterSlot) + self.addchumAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self) + self.addchumAction.triggered.connect(self.addChumSlot) + self.banuserAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/banuser"], self) + self.banuserAction.triggered.connect(self.banSelectedUser) + self.opAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/opuser"], self) + self.opAction.triggered.connect(self.opSelectedUser) + self.voiceAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/voiceuser"], self) + self.voiceAction.triggered.connect(self.voiceSelectedUser) + self.quirkDisableAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirkkill"], self) + self.quirkDisableAction.triggered.connect(self.killQuirkUser) self.userlist.optionsMenu.addAction(self.pesterChumAction) self.userlist.optionsMenu.addAction(self.addchumAction) # ban & op list added if we are op - self.optionsMenu = QtGui.QMenu(self) - self.oocToggle = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/ooc"], self) + self.optionsMenu = QtWidgets.QMenu(self) + self.oocToggle = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/ooc"], self) self.oocToggle.setCheckable(True) - self.connect(self.oocToggle, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleOOC(bool)')) - self.quirksOff = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"], self) + self.oocToggle.toggled[bool].connect(self.toggleOOC) + self.quirksOff = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"], self) self.quirksOff.setCheckable(True) - self.connect(self.quirksOff, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleQuirks(bool)')) - self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self) - self.connect(self.logchum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('openChumLogs()')) - self.invitechum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/invitechum"], self) - self.connect(self.invitechum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('inviteChums()')) + self.quirksOff.toggled[bool].connect(self.toggleQuirks) + self.logchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self) + self.logchum.triggered.connect(self.openChumLogs) + self.invitechum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/invitechum"], self) + self.invitechum.triggered.connect(self.inviteChums) - self._beepToggle = QtGui.QAction("Beep on Message", self) + self._beepToggle = QtWidgets.QAction("Beep on Message", self) self._beepToggle.setCheckable(True) - self.connect(self._beepToggle, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleBeep(bool)')) + self._beepToggle.toggled[bool].connect(self.toggleBeep) - self._flashToggle = QtGui.QAction("Flash on Message", self) + self._flashToggle = QtWidgets.QAction("Flash on Message", self) self._flashToggle.setCheckable(True) - self.connect(self._flashToggle, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleFlash(bool)')) + self._flashToggle.toggled[bool].connect(self.toggleFlash) - self._muteToggle = QtGui.QAction("Mute Notifications", self) + self._muteToggle = QtWidgets.QAction("Mute Notifications", self) self._muteToggle.setCheckable(True) - self.connect(self._muteToggle, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleMute(bool)')) + self._muteToggle.toggled[bool].connect(self.toggleMute) self.optionsMenu.addAction(self.quirksOff) self.optionsMenu.addAction(self.oocToggle) @@ -438,23 +426,19 @@ class PesterMemo(PesterConvo): self.optionsMenu.addAction(self.logchum) self.optionsMenu.addAction(self.invitechum) - self.chanModeMenu = QtGui.QMenu(self.mainwindow.theme["main/menus/rclickchumlist/memosetting"], self) - self.chanNoquirks = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memonoquirk"], self) + self.chanModeMenu = QtWidgets.QMenu(self.mainwindow.theme["main/menus/rclickchumlist/memosetting"], self) + self.chanNoquirks = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memonoquirk"], self) self.chanNoquirks.setCheckable(True) - self.connect(self.chanNoquirks, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('noquirksChan(bool)')) - self.chanHide = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memohidden"], self) + self.chanNoquirks.toggled[bool].connect(self.noquirksChan) + self.chanHide = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memohidden"], self) self.chanHide.setCheckable(True) - self.connect(self.chanHide, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('hideChan(bool)')) - self.chanInvite = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memoinvite"], self) + self.chanHide.toggled[bool].connect(self.hideChan) + self.chanInvite = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memoinvite"], self) self.chanInvite.setCheckable(True) - self.connect(self.chanInvite, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('inviteChan(bool)')) - self.chanMod = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memomute"], self) + self.chanInvite.toggled[bool].connect(self.inviteChan) + self.chanMod = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memomute"], self) self.chanMod.setCheckable(True) - self.connect(self.chanMod, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('modChan(bool)')) + self.chanMod.toggled[bool].connect(self.modChan) self.chanModeMenu.addAction(self.chanNoquirks) self.chanModeMenu.addAction(self.chanHide) self.chanModeMenu.addAction(self.chanInvite) @@ -464,33 +448,28 @@ class PesterMemo(PesterConvo): self.timeinput = TimeInput(self.timeslider, self) self.timeinput.setText(timestr) self.timeinput.setSlider() - self.timetravel = QtGui.QPushButton("GO", self) - self.timeclose = QtGui.QPushButton("CLOSE", self) - self.timeswitchl = QtGui.QPushButton(self) - self.timeswitchr = QtGui.QPushButton(self) + self.timetravel = QtWidgets.QPushButton("GO", self) + self.timeclose = QtWidgets.QPushButton("CLOSE", self) + self.timeswitchl = QtWidgets.QPushButton(self) + self.timeswitchr = QtWidgets.QPushButton(self) - self.connect(self.timetravel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('sendtime()')) - self.connect(self.timeclose, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('smashclock()')) - self.connect(self.timeswitchl, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('prevtime()')) - self.connect(self.timeswitchr, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('nexttime()')) + self.timetravel.clicked.connect(self.sendtime) + self.timeclose.clicked.connect(self.smashclock) + self.timeswitchl.clicked.connect(self.prevtime) + self.timeswitchr.clicked.connect(self.nexttime) self.times = {} self.initTheme(self.mainwindow.theme) # connect - self.connect(self.textInput, QtCore.SIGNAL('returnPressed()'), - self, QtCore.SLOT('sentMessage()')) + self.textInput.returnPressed.connect(self.sentMessage) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.textArea) layout_0.addWidget(self.textInput) - layout_1 = QtGui.QHBoxLayout() + layout_1 = QtWidgets.QHBoxLayout() layout_1.addLayout(layout_0) layout_1.addWidget(self.miniUserlist) layout_1.addWidget(self.userlist) @@ -498,14 +477,14 @@ class PesterMemo(PesterConvo): # layout_1 = QtGui.QGridLayout() # layout_1.addWidget(self.timeslider, 0, 1, QtCore.Qt.AlignHCenter) # layout_1.addWidget(self.timeinput, 1, 0, 1, 3) - layout_2 = QtGui.QHBoxLayout() + layout_2 = QtWidgets.QHBoxLayout() layout_2.addWidget(self.timeslider) layout_2.addWidget(self.timeinput) layout_2.addWidget(self.timetravel) layout_2.addWidget(self.timeclose) layout_2.addWidget(self.timeswitchl) layout_2.addWidget(self.timeswitchr) - self.layout = QtGui.QVBoxLayout() + self.layout = QtWidgets.QVBoxLayout() self.layout.addWidget(self.channelLabel) self.layout.addLayout(layout_1) @@ -595,9 +574,9 @@ class PesterMemo(PesterConvo): self.userlist.optionsMenu.setStyleSheet(theme["main/defaultwindow/style"]) scrolls = "width: 12px; height: 12px; border: 0; padding: 0;" - if theme.has_key("main/chums/scrollbar"): + if "main/chums/scrollbar" in theme: self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["memos/userlist/style"], theme["main/chums/scrollbar/style"] + scrolls, theme["main/chums/scrollbar/handle"], theme["main/chums/scrollbar/downarrow"], theme["main/chums/scrollbar/uparrow"], theme["main/chums/scrollbar/uarrowstyle"], theme["main/chums/scrollbar/darrowstyle"] )) - elif theme.has_key("convo/scrollbar"): + elif "convo/scrollbar" in theme: self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["memos/userlist/style"], theme["convo/scrollbar/style"] + scrolls, theme["convo/scrollbar/handle"], "display:none;", "display:none;", "display:none;", "display:none;" )) else: self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s }" % (theme["memos/userlist/style"], scrolls, "background-color: black;")) @@ -684,7 +663,7 @@ class PesterMemo(PesterConvo): elif handle[0] == '&': admin = True handle = handle[1:] - item = QtGui.QListWidgetItem(handle) + item = QtWidgets.QListWidgetItem(handle) if handle == self.mainwindow.profile().handle: color = self.mainwindow.profile().color else: @@ -720,7 +699,7 @@ class PesterMemo(PesterConvo): systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"]) chum = self.mainwindow.profile() opchum = PesterProfile(op) - if self.times.has_key(op): + if op in self.times: opgrammar = self.times[op].getGrammar() elif op == self.mainwindow.profile().handle: opgrammar = self.time.getGrammar() @@ -815,7 +794,7 @@ class PesterMemo(PesterConvo): else: timed = timeProtocol(cmd) - if self.times.has_key(handle): + if handle in self.times: if close is not None: if close in self.times[handle]: self.times[handle].setCurrent(close) @@ -835,13 +814,13 @@ class PesterMemo(PesterConvo): @QtCore.pyqtSlot() def sentMessage(self): - text = unicode(self.textInput.text()) + text = str(self.textInput.text()) return parsetools.kxhandleInput(self, text, flavor="memos") - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def namesUpdated(self, channel): - c = unicode(channel) + c = str(channel) if c.lower() != self.channel.lower(): return # get namesdb namesdb = self.mainwindow.namesdb @@ -849,28 +828,27 @@ class PesterMemo(PesterConvo): self.userlist.clear() for n in self.mainwindow.namesdb[self.channel]: self.addUser(n) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def modesUpdated(self, channel, modes): - c = unicode(channel) + c = str(channel) if c.lower() == self.channel.lower(): self.updateChanModes(modes, None) - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def closeInviteOnly(self, channel): - c = unicode(channel) + c = str(channel) if c.lower() == self.channel.lower(): - self.disconnect(self.mainwindow, QtCore.SIGNAL('inviteOnlyChan(QString)'), - self, QtCore.SLOT('closeInviteOnly(QString)')) + self.mainwindow.inviteOnlyChan['QString'].disconnect(self.closeInviteOnly) if self.parent(): - print self.channel + print(self.channel) i = self.parent().tabIndices[self.channel] self.parent().tabClose(i) else: self.close() - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setText("%s: Invites only!" % (c)) msgbox.setInformativeText("This channel is invite-only. You must get an invitation from someone on the inside before entering.") - msgbox.setStandardButtons(QtGui.QMessageBox.Ok) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) ret = msgbox.exec_() def quirkDisable(self, op, msg): @@ -883,7 +861,7 @@ class PesterMemo(PesterConvo): systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"]) chum = self.mainwindow.profile() opchum = PesterProfile(op) - if self.times.has_key(op): + if op in self.times: opgrammar = self.times[op].getGrammar() elif op == self.mainwindow.profile().handle: opgrammar = self.time.getGrammar() @@ -899,12 +877,12 @@ class PesterMemo(PesterConvo): chum = self.mainwindow.profile() ttracker = self.time curtime = self.time.getTime() - elif self.times.has_key(h): + elif h in self.times: ttracker = self.times[h] else: ttracker = TimeTracker(timedelta(0)) opchum = PesterProfile(op) - if self.times.has_key(op): + if op in self.times: opgrammar = self.times[op].getGrammar() elif op == self.mainwindow.profile().handle: opgrammar = self.time.getGrammar() @@ -933,11 +911,11 @@ class PesterMemo(PesterConvo): self.mainwindow.chatlog.log(self.channel, msg) del self.netsplit - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString, QString) def userPresentChange(self, handle, channel, update): - h = unicode(handle) - c = unicode(channel) - update = unicode(update) + h = str(handle) + c = str(channel) + update = str(update) if update[0:4] == "kick": # yeah, i'm lazy. l = update.split(":") update = l[0] @@ -968,7 +946,7 @@ class PesterMemo(PesterConvo): for c in chums: chum = PesterProfile(h) self.userlist.takeItem(self.userlist.row(c)) - if not self.times.has_key(h): + if h not in self.times: self.times[h] = TimeTracker(timedelta(0)) allinitials = [] while self.times[h].getTime() is not None: @@ -1002,13 +980,13 @@ class PesterMemo(PesterConvo): chum = self.mainwindow.profile() ttracker = self.time curtime = self.time.getTime() - elif self.times.has_key(h): + elif h in self.times: ttracker = self.times[h] else: ttracker = TimeTracker(timedelta(0)) allinitials = [] opchum = PesterProfile(op) - if self.times.has_key(op): + if op in self.times: opgrammar = self.times[op].getGrammar() elif op == self.mainwindow.profile().handle: opgrammar = self.time.getGrammar() @@ -1024,13 +1002,13 @@ class PesterMemo(PesterConvo): if chum is self.mainwindow.profile(): # are you next? - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setText(self.mainwindow.theme["convo/text/kickedmemo"]) msgbox.setInformativeText("press 0k to rec0nnect or cancel to absc0nd") - msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) # Find the OK button and make it default for b in msgbox.buttons(): - if msgbox.buttonRole(b) == QtGui.QMessageBox.AcceptRole: + if msgbox.buttonRole(b) == QtWidgets.QMessageBox.AcceptRole: # We found the 'OK' button, set it as the default b.setDefault(True) b.setAutoDefault(True) @@ -1039,7 +1017,7 @@ class PesterMemo(PesterConvo): b.setFocus() break ret = msgbox.exec_() - if ret == QtGui.QMessageBox.Ok: + if ret == QtWidgets.QMessageBox.Ok: self.userlist.clear() self.time = TimeTracker(curtime) self.resetSlider(curtime) @@ -1049,7 +1027,7 @@ class PesterMemo(PesterConvo): msg = me.memoopenmsg(systemColor, self.time.getTime(), self.time.getGrammar(), self.mainwindow.theme["convo/text/openmemo"], self.channel) self.textArea.append(convertTags(msg)) self.mainwindow.chatlog.log(self.channel, msg) - elif ret == QtGui.QMessageBox.Cancel: + elif ret == QtWidgets.QMessageBox.Cancel: if self.parent(): i = self.parent().tabIndices[self.channel] self.parent().tabClose(i) @@ -1082,7 +1060,7 @@ class PesterMemo(PesterConvo): for c in chums: c.op = True self.iconCrap(c) - if unicode(c.text()) == self.mainwindow.profile().handle: + if str(c.text()) == self.mainwindow.profile().handle: self.userlist.optionsMenu.addAction(self.opAction) self.userlist.optionsMenu.addAction(self.voiceAction) self.userlist.optionsMenu.addAction(self.banuserAction) @@ -1099,7 +1077,7 @@ class PesterMemo(PesterConvo): for c in chums: c.op = False self.iconCrap(c) - if unicode(c.text()) == self.mainwindow.profile().handle: + if str(c.text()) == self.mainwindow.profile().handle: self.userlist.optionsMenu.removeAction(self.opAction) self.userlist.optionsMenu.removeAction(self.voiceAction) self.userlist.optionsMenu.removeAction(self.banuserAction) @@ -1115,7 +1093,7 @@ class PesterMemo(PesterConvo): for c in chums: c.halfop = True self.iconCrap(c) - if unicode(c.text()) == self.mainwindow.profile().handle: + if str(c.text()) == self.mainwindow.profile().handle: self.userlist.optionsMenu.addAction(self.opAction) self.userlist.optionsMenu.addAction(self.voiceAction) self.userlist.optionsMenu.addAction(self.banuserAction) @@ -1132,7 +1110,7 @@ class PesterMemo(PesterConvo): for c in chums: c.halfop = False self.iconCrap(c) - if unicode(c.text()) == self.mainwindow.profile().handle: + if str(c.text()) == self.mainwindow.profile().handle: self.userlist.optionsMenu.removeAction(self.opAction) self.userlist.optionsMenu.removeAction(self.voiceAction) self.userlist.optionsMenu.removeAction(self.banuserAction) @@ -1180,40 +1158,40 @@ class PesterMemo(PesterConvo): user = self.userlist.currentItem() if not user: return - user = unicode(user.text()) + user = str(user.text()) self.mainwindow.newConversation(user) @QtCore.pyqtSlot() def addChumSlot(self): if not self.userlist.currentItem(): return - currentChum = PesterProfile(unicode(self.userlist.currentItem().text())) + currentChum = PesterProfile(str(self.userlist.currentItem().text())) self.mainwindow.addChum(currentChum) @QtCore.pyqtSlot() def banSelectedUser(self): if not self.userlist.currentItem(): return - currentHandle = unicode(self.userlist.currentItem().text()) - (reason, ok) = QtGui.QInputDialog.getText(self, "Ban User", "Enter the reason you are banning this user (optional):") + currentHandle = str(self.userlist.currentItem().text()) + (reason, ok) = QtWidgets.QInputDialog.getText(self, "Ban User", "Enter the reason you are banning this user (optional):") if ok: self.mainwindow.kickUser.emit("%s:%s" % (currentHandle, reason), self.channel) @QtCore.pyqtSlot() def opSelectedUser(self): if not self.userlist.currentItem(): return - currentHandle = unicode(self.userlist.currentItem().text()) + currentHandle = str(self.userlist.currentItem().text()) self.mainwindow.setChannelMode.emit(self.channel, "+o", currentHandle) @QtCore.pyqtSlot() def voiceSelectedUser(self): if not self.userlist.currentItem(): return - currentHandle = unicode(self.userlist.currentItem().text()) + currentHandle = str(self.userlist.currentItem().text()) self.mainwindow.setChannelMode.emit(self.channel, "+v", currentHandle) @QtCore.pyqtSlot() def killQuirkUser(self): if not self.userlist.currentItem(): return - currentHandle = unicode(self.userlist.currentItem().text()) + currentHandle = str(self.userlist.currentItem().text()) self.mainwindow.killSomeQuirks.emit(self.channel, currentHandle) def resetSlider(self, time, send=True): @@ -1226,8 +1204,7 @@ class PesterMemo(PesterConvo): def openChumLogs(self): currentChum = self.channel self.mainwindow.chumList.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow) - self.connect(self.mainwindow.chumList.pesterlogviewer, QtCore.SIGNAL('rejected()'), - self.mainwindow.chumList, QtCore.SLOT('closeActiveLog()')) + self.mainwindow.chumList.pesterlogviewer.rejected.connect(self.mainwindow.chumList.closeActiveLog) self.mainwindow.chumList.pesterlogviewer.show() self.mainwindow.chumList.pesterlogviewer.raise_() self.mainwindow.chumList.pesterlogviewer.activateWindow() @@ -1237,9 +1214,9 @@ class PesterMemo(PesterConvo): if not hasattr(self, 'invitechums'): self.invitechums = None if not self.invitechums: - (chum, ok) = QtGui.QInputDialog.getText(self, "Invite to Chat", "Enter the chumhandle of the user you'd like to invite:") + (chum, ok) = QtWidgets.QInputDialog.getText(self, "Invite to Chat", "Enter the chumhandle of the user you'd like to invite:") if ok: - chum = unicode(chum) + chum = str(chum) self.mainwindow.inviteChum.emit(chum, self.channel) self.invitechums = None @@ -1303,7 +1280,7 @@ class PesterMemo(PesterConvo): self.mainwindow.waitingMessages.messageAnswered(self.channel) self.windowClosed.emit(self.title()) - windowClosed = QtCore.pyqtSignal(QtCore.QString) + windowClosed = QtCore.pyqtSignal('QString') timelist = ["0:00", "0:01", "0:02", "0:04", "0:06", "0:10", "0:14", "0:22", "0:30", "0:41", "1:00", "1:34", "2:16", "3:14", "4:13", "4:20", "5:25", "6:12", "7:30", "8:44", "10:25", "11:34", "14:13", "16:12", "17:44", "22:22", "25:10", "33:33", "42:00", "43:14", "50:00", "62:12", "75:00", "88:44", "100", "133", "143", "188", "200", "222", "250", "314", "333", "413", "420", "500", "600", "612", "888", "1000", "1025"] diff --git a/menus.py b/menus.py index b5fcd92..78250b7 100644 --- a/menus.py +++ b/menus.py @@ -1,4 +1,4 @@ -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets import re, ostools from os import remove @@ -7,17 +7,23 @@ from dataobjs import pesterQuirk, PesterProfile from memos import TimeSlider, TimeInput from version import _pcVersion +try: + QString = unicode +except NameError: + # Python 3 + QString = str + _datadir = ostools.getDataDir() -class PesterQuirkItem(QtGui.QTreeWidgetItem): +class PesterQuirkItem(QtWidgets.QTreeWidgetItem): def __init__(self, quirk): parent = None - QtGui.QTreeWidgetItem.__init__(self, parent) + QtWidgets.QTreeWidgetItem.__init__(self, parent) self.quirk = quirk - self.setText(0, unicode(quirk)) + self.setText(0, str(quirk)) def update(self, quirk): self.quirk = quirk - self.setText(0, unicode(quirk)) + self.setText(0, str(quirk)) def __lt__(self, quirkitem): """Sets the order of quirks if auto-sorted by Qt. Obsolete now.""" if self.quirk.type == "prefix": @@ -27,16 +33,15 @@ class PesterQuirkItem(QtGui.QTreeWidgetItem): return True else: return False -class PesterQuirkList(QtGui.QTreeWidget): +class PesterQuirkList(QtWidgets.QTreeWidget): def __init__(self, mainwindow, parent): - QtGui.QTreeWidget.__init__(self, parent) + QtWidgets.QTreeWidget.__init__(self, parent) self.resize(400, 200) # make sure we have access to mainwindow info like profiles self.mainwindow = mainwindow self.setStyleSheet("background:black; color:white;") - self.connect(self, QtCore.SIGNAL('itemChanged(QTreeWidgetItem *, int)'), - self, QtCore.SLOT('changeCheckState()')) + self.itemChanged[QTreeWidgetItem, int].connect(self.changeCheckState) for q in mainwindow.userprofile.quirks: item = PesterQuirkItem(q) @@ -64,10 +69,10 @@ class PesterQuirkList(QtGui.QTreeWidget): if len(found) > 0: found[0].addChild(item) else: - child_1 = QtGui.QTreeWidgetItem([item.quirk.group]) + child_1 = QtWidgets.QTreeWidgetItem([item.quirk.group]) self.addTopLevelItem(child_1) child_1.setFlags(child_1.flags() | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) - child_1.setChildIndicatorPolicy(QtGui.QTreeWidgetItem.DontShowIndicatorWhenChildless) + child_1.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.DontShowIndicatorWhenChildless) child_1.setCheckState(0,0) child_1.setExpanded(True) child_1.addChild(item) @@ -145,15 +150,15 @@ class PesterQuirkList(QtGui.QTreeWidget): for f in found: if not f.isSelected(): continue if not f.parent(): # group - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) msgbox.setObjectName("delquirkwarning") msgbox.setWindowTitle("WARNING!") msgbox.setInformativeText("Are you sure you want to delete the quirk group: %s" % (f.text(0))) - msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) # Find the Cancel button and make it default for b in msgbox.buttons(): - if msgbox.buttonRole(b) == QtGui.QMessageBox.RejectRole: + if msgbox.buttonRole(b) == QtWidgets.QMessageBox.RejectRole: # We found the 'OK' button, set it as the default b.setDefault(True) b.setAutoDefault(True) @@ -162,7 +167,7 @@ class PesterQuirkList(QtGui.QTreeWidget): b.setFocus() break ret = msgbox.exec_() - if ret == QtGui.QMessageBox.Ok: + if ret == QtWidgets.QMessageBox.Ok: self.takeTopLevelItem(self.indexOfTopLevelItem(f)) else: f.parent().takeChild(f.parent().indexOfChild(f)) @@ -173,27 +178,27 @@ class PesterQuirkList(QtGui.QTreeWidget): if not hasattr(self, 'addgroupdialog'): self.addgroupdialog = None if not self.addgroupdialog: - (gname, ok) = QtGui.QInputDialog.getText(self, "Add Group", "Enter a name for the new quirk group:") + (gname, ok) = QtWidgets.QInputDialog.getText(self, "Add Group", "Enter a name for the new quirk group:") if ok: - gname = unicode(gname) + gname = str(gname) if re.search("[^A-Za-z0-9_\s]", gname) is not None: - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setInformativeText("THIS IS NOT A VALID GROUP NAME") - msgbox.setStandardButtons(QtGui.QMessageBox.Ok) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) ret = msgbox.exec_() self.addgroupdialog = None return found = self.findItems(gname, QtCore.Qt.MatchExactly) if found: - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setInformativeText("THIS QUIRK GROUP ALREADY EXISTS") - msgbox.setStandardButtons(QtGui.QMessageBox.Ok) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) ret = msgbox.exec_() return - child_1 = QtGui.QTreeWidgetItem([gname]) + child_1 = QtWidgets.QTreeWidgetItem([gname]) self.addTopLevelItem(child_1) child_1.setFlags(child_1.flags() | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) - child_1.setChildIndicatorPolicy(QtGui.QTreeWidgetItem.DontShowIndicatorWhenChildless) + child_1.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.DontShowIndicatorWhenChildless) child_1.setCheckState(0,0) child_1.setExpanded(True) @@ -224,9 +229,9 @@ from convo import PesterInput, PesterText from parsetools import convertTags, lexMessage, splitMessage, mecmd, colorBegin, colorEnd, img2smiley, smiledict import parsetools from dataobjs import pesterQuirks, PesterHistory -class QuirkTesterWindow(QtGui.QDialog): +class QuirkTesterWindow(QtWidgets.QDialog): def __init__(self, parent): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.prnt = parent self.mainwindow = parent.mainwindow self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) @@ -237,14 +242,13 @@ class QuirkTesterWindow(QtGui.QDialog): self.textInput = PesterInput(self.mainwindow.theme, self) self.textInput.setFocus() - self.connect(self.textInput, QtCore.SIGNAL('returnPressed()'), - self, QtCore.SLOT('sentMessage()')) + self.textInput.returnPressed.connect(self.sentMessage) self.chumopen = True self.chum = self.mainwindow.profile() self.history = PesterHistory() - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.textArea) layout_0.addWidget(self.textInput) self.setLayout(layout_0) @@ -256,12 +260,12 @@ class QuirkTesterWindow(QtGui.QDialog): pass @QtCore.pyqtSlot() def sentMessage(self): - text = unicode(self.textInput.text()) + text = str(self.textInput.text()) return parsetools.kxhandleInput(self, text, "menus") def addMessage(self, msg, me=True): - if type(msg) in [str, unicode]: + if type(msg) in [str, str]: lexmsg = lexMessage(msg) else: lexmsg = msg @@ -274,174 +278,167 @@ class QuirkTesterWindow(QtGui.QDialog): def closeEvent(self, event): self.parent().quirktester = None -class PesterQuirkTypes(QtGui.QDialog): +class PesterQuirkTypes(QtWidgets.QDialog): def __init__(self, parent, quirk=None): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.mainwindow = parent.mainwindow self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) self.setWindowTitle("Quirk Wizard") self.resize(500,310) self.quirk = quirk - self.pages = QtGui.QStackedWidget(self) + self.pages = QtWidgets.QStackedWidget(self) - self.next = QtGui.QPushButton("Next", self) + self.next = QtWidgets.QPushButton("Next", self) self.next.setDefault(True) - self.connect(self.next, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('nextPage()')) - self.back = QtGui.QPushButton("Back", self) + self.__next__.clicked.connect(self.nextPage) + self.back = QtWidgets.QPushButton("Back", self) self.back.setEnabled(False) - self.connect(self.back, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('backPage()')) - self.cancel = QtGui.QPushButton("Cancel", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_2 = QtGui.QHBoxLayout() + self.back.clicked.connect(self.backPage) + self.cancel = QtWidgets.QPushButton("Cancel", self) + self.cancel.clicked.connect(self.reject) + layout_2 = QtWidgets.QHBoxLayout() layout_2.setAlignment(QtCore.Qt.AlignRight) layout_2.addWidget(self.back) - layout_2.addWidget(self.next) + layout_2.addWidget(self.__next__) layout_2.addSpacing(5) layout_2.addWidget(self.cancel) - vr = QtGui.QFrame() - vr.setFrameShape(QtGui.QFrame.VLine) - vr.setFrameShadow(QtGui.QFrame.Sunken) - vr2 = QtGui.QFrame() - vr2.setFrameShape(QtGui.QFrame.VLine) - vr2.setFrameShadow(QtGui.QFrame.Sunken) + vr = QtWidgets.QFrame() + vr.setFrameShape(QtWidgets.QFrame.VLine) + vr.setFrameShadow(QtWidgets.QFrame.Sunken) + vr2 = QtWidgets.QFrame() + vr2.setFrameShape(QtWidgets.QFrame.VLine) + vr2.setFrameShadow(QtWidgets.QFrame.Sunken) - self.funclist = QtGui.QListWidget(self) + self.funclist = QtWidgets.QListWidget(self) self.funclist.setStyleSheet("color: #000000; background-color: #FFFFFF;") - self.funclist2 = QtGui.QListWidget(self) + self.funclist2 = QtWidgets.QListWidget(self) self.funclist2.setStyleSheet("color: #000000; background-color: #FFFFFF;") from parsetools import quirkloader - funcs = [q+"()" for q in quirkloader.quirks.keys()] + funcs = [q+"()" for q in list(quirkloader.quirks.keys())] funcs.sort() self.funclist.addItems(funcs) self.funclist2.addItems(funcs) - self.reloadQuirkFuncButton = QtGui.QPushButton("RELOAD FUNCTIONS", self) - self.connect(self.reloadQuirkFuncButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reloadQuirkFuncSlot()')) - self.reloadQuirkFuncButton2 = QtGui.QPushButton("RELOAD FUNCTIONS", self) - self.connect(self.reloadQuirkFuncButton2, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reloadQuirkFuncSlot()')) + self.reloadQuirkFuncButton = QtWidgets.QPushButton("RELOAD FUNCTIONS", self) + self.reloadQuirkFuncButton.clicked.connect(self.reloadQuirkFuncSlot) + self.reloadQuirkFuncButton2 = QtWidgets.QPushButton("RELOAD FUNCTIONS", self) + self.reloadQuirkFuncButton2.clicked.connect(self.reloadQuirkFuncSlot) self.funclist.setMaximumWidth(160) self.funclist.resize(160,50) self.funclist2.setMaximumWidth(160) self.funclist2.resize(160,50) - layout_f = QtGui.QVBoxLayout() - layout_f.addWidget(QtGui.QLabel("Available Regexp\nFunctions")) + layout_f = QtWidgets.QVBoxLayout() + layout_f.addWidget(QtWidgets.QLabel("Available Regexp\nFunctions")) layout_f.addWidget(self.funclist) layout_f.addWidget(self.reloadQuirkFuncButton) - layout_g = QtGui.QVBoxLayout() - layout_g.addWidget(QtGui.QLabel("Available Regexp\nFunctions")) + layout_g = QtWidgets.QVBoxLayout() + layout_g.addWidget(QtWidgets.QLabel("Available Regexp\nFunctions")) layout_g.addWidget(self.funclist2) layout_g.addWidget(self.reloadQuirkFuncButton2) # Pages # Type select - widget = QtGui.QWidget() + widget = QtWidgets.QWidget() self.pages.addWidget(widget) - layout_select = QtGui.QVBoxLayout(widget) + layout_select = QtWidgets.QVBoxLayout(widget) layout_select.setAlignment(QtCore.Qt.AlignTop) self.radios = [] - self.radios.append(QtGui.QRadioButton("Prefix", self)) - self.radios.append(QtGui.QRadioButton("Suffix", self)) - self.radios.append(QtGui.QRadioButton("Simple Replace", self)) - self.radios.append(QtGui.QRadioButton("Regexp Replace", self)) - self.radios.append(QtGui.QRadioButton("Random Replace", self)) - self.radios.append(QtGui.QRadioButton("Mispeller", self)) + self.radios.append(QtWidgets.QRadioButton("Prefix", self)) + self.radios.append(QtWidgets.QRadioButton("Suffix", self)) + self.radios.append(QtWidgets.QRadioButton("Simple Replace", self)) + self.radios.append(QtWidgets.QRadioButton("Regexp Replace", self)) + self.radios.append(QtWidgets.QRadioButton("Random Replace", self)) + self.radios.append(QtWidgets.QRadioButton("Mispeller", self)) - layout_select.addWidget(QtGui.QLabel("Select Quirk Type:")) + layout_select.addWidget(QtWidgets.QLabel("Select Quirk Type:")) for r in self.radios: layout_select.addWidget(r) # Prefix - widget = QtGui.QWidget() + widget = QtWidgets.QWidget() self.pages.addWidget(widget) - layout_prefix = QtGui.QVBoxLayout(widget) + layout_prefix = QtWidgets.QVBoxLayout(widget) layout_prefix.setAlignment(QtCore.Qt.AlignTop) - layout_prefix.addWidget(QtGui.QLabel("Prefix")) - layout_3 = QtGui.QHBoxLayout() - layout_3.addWidget(QtGui.QLabel("Value:")) - layout_3.addWidget(QtGui.QLineEdit()) + layout_prefix.addWidget(QtWidgets.QLabel("Prefix")) + layout_3 = QtWidgets.QHBoxLayout() + layout_3.addWidget(QtWidgets.QLabel("Value:")) + layout_3.addWidget(QtWidgets.QLineEdit()) layout_prefix.addLayout(layout_3) # Suffix - widget = QtGui.QWidget() + widget = QtWidgets.QWidget() self.pages.addWidget(widget) - layout_suffix = QtGui.QVBoxLayout(widget) + layout_suffix = QtWidgets.QVBoxLayout(widget) layout_suffix.setAlignment(QtCore.Qt.AlignTop) - layout_suffix.addWidget(QtGui.QLabel("Suffix")) - layout_3 = QtGui.QHBoxLayout() - layout_3.addWidget(QtGui.QLabel("Value:")) - layout_3.addWidget(QtGui.QLineEdit()) + layout_suffix.addWidget(QtWidgets.QLabel("Suffix")) + layout_3 = QtWidgets.QHBoxLayout() + layout_3.addWidget(QtWidgets.QLabel("Value:")) + layout_3.addWidget(QtWidgets.QLineEdit()) layout_suffix.addLayout(layout_3) # Simple Replace - widget = QtGui.QWidget() + widget = QtWidgets.QWidget() self.pages.addWidget(widget) - layout_replace = QtGui.QVBoxLayout(widget) + layout_replace = QtWidgets.QVBoxLayout(widget) layout_replace.setAlignment(QtCore.Qt.AlignTop) - layout_replace.addWidget(QtGui.QLabel("Simple Replace")) - layout_3 = QtGui.QHBoxLayout() - layout_3.addWidget(QtGui.QLabel("Replace:")) - layout_3.addWidget(QtGui.QLineEdit()) + layout_replace.addWidget(QtWidgets.QLabel("Simple Replace")) + layout_3 = QtWidgets.QHBoxLayout() + layout_3.addWidget(QtWidgets.QLabel("Replace:")) + layout_3.addWidget(QtWidgets.QLineEdit()) layout_replace.addLayout(layout_3) - layout_3 = QtGui.QHBoxLayout() - layout_3.addWidget(QtGui.QLabel("With:")) - layout_3.addWidget(QtGui.QLineEdit()) + layout_3 = QtWidgets.QHBoxLayout() + layout_3.addWidget(QtWidgets.QLabel("With:")) + layout_3.addWidget(QtWidgets.QLineEdit()) layout_replace.addLayout(layout_3) # Regexp Replace - widget = QtGui.QWidget() + widget = QtWidgets.QWidget() self.pages.addWidget(widget) - layout_all = QtGui.QHBoxLayout(widget) - layout_regexp = QtGui.QVBoxLayout() + layout_all = QtWidgets.QHBoxLayout(widget) + layout_regexp = QtWidgets.QVBoxLayout() layout_regexp.setAlignment(QtCore.Qt.AlignTop) - layout_regexp.addWidget(QtGui.QLabel("Regexp Replace")) - layout_3 = QtGui.QHBoxLayout() - layout_3.addWidget(QtGui.QLabel("Regexp:")) - layout_3.addWidget(QtGui.QLineEdit()) + layout_regexp.addWidget(QtWidgets.QLabel("Regexp Replace")) + layout_3 = QtWidgets.QHBoxLayout() + layout_3.addWidget(QtWidgets.QLabel("Regexp:")) + layout_3.addWidget(QtWidgets.QLineEdit()) layout_regexp.addLayout(layout_3) - layout_3 = QtGui.QHBoxLayout() - layout_3.addWidget(QtGui.QLabel("Replace With:")) - layout_3.addWidget(QtGui.QLineEdit()) + layout_3 = QtWidgets.QHBoxLayout() + layout_3.addWidget(QtWidgets.QLabel("Replace With:")) + layout_3.addWidget(QtWidgets.QLineEdit()) layout_regexp.addLayout(layout_3) layout_all.addLayout(layout_f) layout_all.addWidget(vr) layout_all.addLayout(layout_regexp) # Random Replace - widget = QtGui.QWidget() + widget = QtWidgets.QWidget() self.pages.addWidget(widget) - layout_all = QtGui.QHBoxLayout(widget) - layout_random = QtGui.QVBoxLayout() + layout_all = QtWidgets.QHBoxLayout(widget) + layout_random = QtWidgets.QVBoxLayout() layout_random.setAlignment(QtCore.Qt.AlignTop) - layout_random.addWidget(QtGui.QLabel("Random Replace")) - layout_5 = QtGui.QHBoxLayout() - regexpl = QtGui.QLabel("Regexp:", self) - self.regexp = QtGui.QLineEdit("", self) + layout_random.addWidget(QtWidgets.QLabel("Random Replace")) + layout_5 = QtWidgets.QHBoxLayout() + regexpl = QtWidgets.QLabel("Regexp:", self) + self.regexp = QtWidgets.QLineEdit("", self) layout_5.addWidget(regexpl) layout_5.addWidget(self.regexp) - replacewithl = QtGui.QLabel("Replace With:", self) + replacewithl = QtWidgets.QLabel("Replace With:", self) layout_all.addLayout(layout_g) layout_all.addWidget(vr2) layout_all.addLayout(layout_random) - layout_6 = QtGui.QVBoxLayout() - layout_7 = QtGui.QHBoxLayout() - self.replacelist = QtGui.QListWidget(self) - self.replaceinput = QtGui.QLineEdit(self) - addbutton = QtGui.QPushButton("ADD", self) - self.connect(addbutton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('addRandomString()')) - removebutton = QtGui.QPushButton("REMOVE", self) - self.connect(removebutton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('removeRandomString()')) + layout_6 = QtWidgets.QVBoxLayout() + layout_7 = QtWidgets.QHBoxLayout() + self.replacelist = QtWidgets.QListWidget(self) + self.replaceinput = QtWidgets.QLineEdit(self) + addbutton = QtWidgets.QPushButton("ADD", self) + addbutton.clicked.connect(self.addRandomString) + removebutton = QtWidgets.QPushButton("REMOVE", self) + removebutton.clicked.connect(self.removeRandomString) layout_7.addWidget(addbutton) layout_7.addWidget(removebutton) layout_6.addLayout(layout_5) @@ -452,29 +449,28 @@ class PesterQuirkTypes(QtGui.QDialog): layout_random.addLayout(layout_6) # Misspeller - widget = QtGui.QWidget() + widget = QtWidgets.QWidget() self.pages.addWidget(widget) - layout_mispeller = QtGui.QVBoxLayout(widget) + layout_mispeller = QtWidgets.QVBoxLayout(widget) layout_mispeller.setAlignment(QtCore.Qt.AlignTop) - layout_mispeller.addWidget(QtGui.QLabel("Mispeller")) - layout_1 = QtGui.QHBoxLayout() - zero = QtGui.QLabel("1%", self) - hund = QtGui.QLabel("100%", self) - self.current = QtGui.QLabel("50%", self) + layout_mispeller.addWidget(QtWidgets.QLabel("Mispeller")) + layout_1 = QtWidgets.QHBoxLayout() + zero = QtWidgets.QLabel("1%", self) + hund = QtWidgets.QLabel("100%", self) + self.current = QtWidgets.QLabel("50%", self) self.current.setAlignment(QtCore.Qt.AlignHCenter) - self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, self) + self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self) self.slider.setMinimum(1) self.slider.setMaximum(100) self.slider.setValue(50) - self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), - self, QtCore.SLOT('printValue(int)')) + self.slider.valueChanged[int].connect(self.printValue) layout_1.addWidget(zero) layout_1.addWidget(self.slider) layout_1.addWidget(hund) layout_mispeller.addLayout(layout_1) layout_mispeller.addWidget(self.current) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.pages) layout_0.addLayout(layout_2) @@ -497,7 +493,7 @@ class PesterQuirkTypes(QtGui.QDialog): elif q["type"] == "random": self.regexp.setText(q["from"]) for v in q["randomlist"]: - item = QtGui.QListWidgetItem(v, self.replacelist) + item = QtWidgets.QListWidgetItem(v, self.replacelist) elif q["type"] == "spelling": self.slider.setValue(q["percentage"]) @@ -538,8 +534,8 @@ class PesterQuirkTypes(QtGui.QDialog): self.current.setText(str(value)+"%") @QtCore.pyqtSlot() def addRandomString(self): - text = unicode(self.replaceinput.text()) - item = QtGui.QListWidgetItem(text, self.replacelist) + text = str(self.replaceinput.text()) + item = QtWidgets.QListWidgetItem(text, self.replacelist) self.replaceinput.setText("") self.replaceinput.setFocus() @QtCore.pyqtSlot() @@ -554,16 +550,16 @@ class PesterQuirkTypes(QtGui.QDialog): def reloadQuirkFuncSlot(self): from parsetools import reloadQuirkFunctions, quirkloader reloadQuirkFunctions() - funcs = [q+"()" for q in quirkloader.quirks.keys()] + funcs = [q+"()" for q in list(quirkloader.quirks.keys())] funcs.sort() self.funclist.clear() self.funclist.addItems(funcs) self.funclist2.clear() self.funclist2.addItems(funcs) -class PesterChooseQuirks(QtGui.QDialog): +class PesterChooseQuirks(QtWidgets.QDialog): def __init__(self, config, theme, parent): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.setModal(False) self.config = config self.theme = theme @@ -573,61 +569,52 @@ class PesterChooseQuirks(QtGui.QDialog): self.quirkList = PesterQuirkList(self.mainwindow, self) - self.addQuirkButton = QtGui.QPushButton("ADD QUIRK", self) - self.connect(self.addQuirkButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('addQuirkDialog()')) + self.addQuirkButton = QtWidgets.QPushButton("ADD QUIRK", self) + self.addQuirkButton.clicked.connect(self.addQuirkDialog) - self.upShiftButton = QtGui.QPushButton("^", self) - self.downShiftButton = QtGui.QPushButton("v", self) + self.upShiftButton = QtWidgets.QPushButton("^", self) + self.downShiftButton = QtWidgets.QPushButton("v", self) self.upShiftButton.setToolTip("Move quirk up one") self.downShiftButton.setToolTip("Move quirk down one") - self.connect(self.upShiftButton, QtCore.SIGNAL('clicked()'), - self.quirkList, QtCore.SLOT('upShiftQuirk()')) - self.connect(self.downShiftButton, QtCore.SIGNAL('clicked()'), - self.quirkList, QtCore.SLOT('downShiftQuirk()')) + self.upShiftButton.clicked.connect(self.quirkList.upShiftQuirk) + self.downShiftButton.clicked.connect(self.quirkList.downShiftQuirk) - self.newGroupButton = QtGui.QPushButton("*", self) + self.newGroupButton = QtWidgets.QPushButton("*", self) self.newGroupButton.setToolTip("New Quirk Group") - self.connect(self.newGroupButton, QtCore.SIGNAL('clicked()'), - self.quirkList, QtCore.SLOT('addQuirkGroup()')) + self.newGroupButton.clicked.connect(self.quirkList.addQuirkGroup) - layout_quirklist = QtGui.QHBoxLayout() #the nude layout quirklist - layout_shiftbuttons = QtGui.QVBoxLayout() #the shift button layout + layout_quirklist = QtWidgets.QHBoxLayout() #the nude layout quirklist + layout_shiftbuttons = QtWidgets.QVBoxLayout() #the shift button layout layout_shiftbuttons.addWidget(self.upShiftButton) layout_shiftbuttons.addWidget(self.newGroupButton) layout_shiftbuttons.addWidget(self.downShiftButton) layout_quirklist.addWidget(self.quirkList) layout_quirklist.addLayout(layout_shiftbuttons) - layout_1 = QtGui.QHBoxLayout() + layout_1 = QtWidgets.QHBoxLayout() layout_1.addWidget(self.addQuirkButton) - self.editSelectedButton = QtGui.QPushButton("EDIT", self) - self.connect(self.editSelectedButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('editSelected()')) - self.removeSelectedButton = QtGui.QPushButton("REMOVE", self) - self.connect(self.removeSelectedButton, QtCore.SIGNAL('clicked()'), - self.quirkList, QtCore.SLOT('removeCurrent()')) - layout_3 = QtGui.QHBoxLayout() + self.editSelectedButton = QtWidgets.QPushButton("EDIT", self) + self.editSelectedButton.clicked.connect(self.editSelected) + self.removeSelectedButton = QtWidgets.QPushButton("REMOVE", self) + self.removeSelectedButton.clicked.connect(self.quirkList.removeCurrent) + layout_3 = QtWidgets.QHBoxLayout() layout_3.addWidget(self.editSelectedButton) layout_3.addWidget(self.removeSelectedButton) - self.ok = QtGui.QPushButton("OK", self) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('accept()')) - self.test = QtGui.QPushButton("TEST QUIRKS", self) - self.connect(self.test, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('testQuirks()')) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_ok = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.accept) + self.test = QtWidgets.QPushButton("TEST QUIRKS", self) + self.test.clicked.connect(self.testQuirks) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + layout_ok = QtWidgets.QHBoxLayout() layout_ok.addWidget(self.cancel) layout_ok.addWidget(self.test) layout_ok.addWidget(self.ok) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addLayout(layout_quirklist) layout_0.addLayout(layout_1) #layout_0.addLayout(layout_2) @@ -675,10 +662,8 @@ class PesterChooseQuirks(QtGui.QDialog): if self.quirkadd: return self.quirkadd = PesterQuirkTypes(self, quirk) - self.connect(self.quirkadd, QtCore.SIGNAL('accepted()'), - self, QtCore.SLOT('addQuirk()')) - self.connect(self.quirkadd, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('closeQuirk()')) + self.quirkadd.accepted.connect(self.addQuirk) + self.quirkadd.rejected.connect(self.closeQuirk) self.quirkadd.show() @QtCore.pyqtSlot() def addQuirk(self): @@ -687,16 +672,16 @@ class PesterChooseQuirks(QtGui.QDialog): vdict["type"] = types[self.quirkadd.pages.currentIndex()-1] page = self.quirkadd.pages.currentWidget().layout() if vdict["type"] in ("prefix","suffix"): - vdict["value"] = unicode(page.itemAt(1).layout().itemAt(1).widget().text()) + vdict["value"] = str(page.itemAt(1).layout().itemAt(1).widget().text()) elif vdict["type"] == "replace": - vdict["from"] = unicode(page.itemAt(1).layout().itemAt(1).widget().text()) - vdict["to"] = unicode(page.itemAt(2).layout().itemAt(1).widget().text()) + vdict["from"] = str(page.itemAt(1).layout().itemAt(1).widget().text()) + vdict["to"] = str(page.itemAt(2).layout().itemAt(1).widget().text()) elif vdict["type"] == "regexp": - vdict["from"] = unicode(page.itemAt(2).layout().itemAt(1).layout().itemAt(1).widget().text()) - vdict["to"] = unicode(page.itemAt(2).layout().itemAt(2).layout().itemAt(1).widget().text()) + vdict["from"] = str(page.itemAt(2).layout().itemAt(1).layout().itemAt(1).widget().text()) + vdict["to"] = str(page.itemAt(2).layout().itemAt(2).layout().itemAt(1).widget().text()) elif vdict["type"] == "random": - vdict["from"] = unicode(self.quirkadd.regexp.text()) - randomlist = [unicode(self.quirkadd.replacelist.item(i).text()) + vdict["from"] = str(self.quirkadd.regexp.text()) + randomlist = [str(self.quirkadd.replacelist.item(i).text()) for i in range(0,self.quirkadd.replacelist.count())] vdict["randomlist"] = randomlist elif vdict["type"] == "spelling": @@ -705,8 +690,8 @@ class PesterChooseQuirks(QtGui.QDialog): if vdict["type"] in ("regexp", "random"): try: re.compile(vdict["from"]) - except re.error, e: - quirkWarning = QtGui.QMessageBox(self) + except re.error as e: + quirkWarning = QtWidgets.QMessageBox(self) quirkWarning.setText("Not a valid regular expression!") quirkWarning.setInformativeText("H3R3S WHY DUMP4SS: %s" % (e)) quirkWarning.exec_() @@ -724,69 +709,64 @@ class PesterChooseQuirks(QtGui.QDialog): def closeQuirk(self): self.quirkadd = None -class PesterChooseTheme(QtGui.QDialog): +class PesterChooseTheme(QtWidgets.QDialog): def __init__(self, config, theme, parent): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.config = config self.theme = theme self.parent = parent self.setStyleSheet(self.theme["main/defaultwindow/style"]) self.setWindowTitle("Pick a theme") - instructions = QtGui.QLabel("Pick a theme:") + instructions = QtWidgets.QLabel("Pick a theme:") avail_themes = config.availableThemes() - self.themeBox = QtGui.QComboBox(self) + self.themeBox = QtWidgets.QComboBox(self) for (i, t) in enumerate(avail_themes): self.themeBox.addItem(t) if t == theme.name: self.themeBox.setCurrentIndex(i) - self.ok = QtGui.QPushButton("OK", self) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('accept()')) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_ok = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.accept) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + layout_ok = QtWidgets.QHBoxLayout() layout_ok.addWidget(self.cancel) layout_ok.addWidget(self.ok) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(instructions) layout_0.addWidget(self.themeBox) layout_0.addLayout(layout_ok) self.setLayout(layout_0) - self.connect(self, QtCore.SIGNAL('accepted()'), - parent, QtCore.SLOT('themeSelected()')) - self.connect(self, QtCore.SIGNAL('rejected()'), - parent, QtCore.SLOT('closeTheme()')) + self.accepted.connect(parent.themeSelected) + self.rejected.connect(parent.closeTheme) -class PesterChooseProfile(QtGui.QDialog): +class PesterChooseProfile(QtWidgets.QDialog): def __init__(self, userprofile, config, theme, parent, collision=None): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.userprofile = userprofile self.theme = theme self.config = config self.parent = parent self.setStyleSheet(self.theme["main/defaultwindow/style"]) - self.currentHandle = QtGui.QLabel("CHANGING FROM %s" % userprofile.chat.handle) - self.chumHandle = QtGui.QLineEdit(self) + self.currentHandle = QtWidgets.QLabel("CHANGING FROM %s" % userprofile.chat.handle) + self.chumHandle = QtWidgets.QLineEdit(self) self.chumHandle.setMinimumWidth(200) self.chumHandle.setObjectName("setprofilehandle") - self.chumHandleLabel = QtGui.QLabel(self.theme["main/mychumhandle/label/text"], self) - self.chumColorButton = QtGui.QPushButton(self) + self.chumHandleLabel = QtWidgets.QLabel(self.theme["main/mychumhandle/label/text"], self) + self.chumColorButton = QtWidgets.QPushButton(self) self.chumColorButton.setObjectName("setprofilecolor") self.chumColorButton.resize(50, 20) self.chumColorButton.setStyleSheet("background: %s" % (userprofile.chat.colorhtml())) self.chumcolor = userprofile.chat.color - self.connect(self.chumColorButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('openColorDialog()')) - layout_1 = QtGui.QHBoxLayout() + self.chumColorButton.clicked.connect(self.openColorDialog) + layout_1 = QtWidgets.QHBoxLayout() layout_1.addWidget(self.chumHandleLabel) layout_1.addWidget(self.chumHandle) layout_1.addWidget(self.chumColorButton) @@ -794,63 +774,58 @@ class PesterChooseProfile(QtGui.QDialog): # available profiles? avail_profiles = self.config.availableProfiles() if avail_profiles: - self.profileBox = QtGui.QComboBox(self) + self.profileBox = QtWidgets.QComboBox(self) self.profileBox.addItem("Choose a profile...") for p in avail_profiles: self.profileBox.addItem(p.chat.handle) else: self.profileBox = None - self.defaultcheck = QtGui.QCheckBox(self) - self.defaultlabel = QtGui.QLabel("Set This Profile As Default", self) - layout_2 = QtGui.QHBoxLayout() + self.defaultcheck = QtWidgets.QCheckBox(self) + self.defaultlabel = QtWidgets.QLabel("Set This Profile As Default", self) + layout_2 = QtWidgets.QHBoxLayout() layout_2.addWidget(self.defaultlabel) layout_2.addWidget(self.defaultcheck) - self.ok = QtGui.QPushButton("OK", self) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('validateProfile()')) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) + self.ok.clicked.connect(self.validateProfile) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) if not collision and avail_profiles: - self.delete = QtGui.QPushButton("DELETE", self) - self.connect(self.delete, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('deleteProfile()')) - layout_ok = QtGui.QHBoxLayout() + self.delete = QtWidgets.QPushButton("DELETE", self) + self.delete.clicked.connect(self.deleteProfile) + layout_ok = QtWidgets.QHBoxLayout() layout_ok.addWidget(self.cancel) layout_ok.addWidget(self.ok) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() if collision: - collision_warning = QtGui.QLabel("%s is taken already! Pick a new profile." % (collision)) + collision_warning = QtWidgets.QLabel("%s is taken already! Pick a new profile." % (collision)) layout_0.addWidget(collision_warning) else: layout_0.addWidget(self.currentHandle, alignment=QtCore.Qt.AlignHCenter) layout_0.addLayout(layout_1) if avail_profiles: - profileLabel = QtGui.QLabel("Or choose an existing profile:", self) + profileLabel = QtWidgets.QLabel("Or choose an existing profile:", self) layout_0.addWidget(profileLabel) layout_0.addWidget(self.profileBox) layout_0.addLayout(layout_ok) if not collision and avail_profiles: layout_0.addWidget(self.delete) layout_0.addLayout(layout_2) - self.errorMsg = QtGui.QLabel(self) + self.errorMsg = QtWidgets.QLabel(self) self.errorMsg.setObjectName("errormsg") self.errorMsg.setStyleSheet("color:red;") layout_0.addWidget(self.errorMsg) self.setLayout(layout_0) - self.connect(self, QtCore.SIGNAL('accepted()'), - parent, QtCore.SLOT('profileSelected()')) - self.connect(self, QtCore.SIGNAL('rejected()'), - parent, QtCore.SLOT('closeProfile()')) + self.accepted.connect(parent.profileSelected) + self.rejected.connect(parent.closeProfile) @QtCore.pyqtSlot() def openColorDialog(self): - self.colorDialog = QtGui.QColorDialog(self) + self.colorDialog = QtWidgets.QColorDialog(self) color = self.colorDialog.getColor(initial=self.userprofile.chat.color) self.chumColorButton.setStyleSheet("background: %s" % color.name()) self.chumcolor = color @@ -859,7 +834,7 @@ class PesterChooseProfile(QtGui.QDialog): @QtCore.pyqtSlot() def validateProfile(self): if not self.profileBox or self.profileBox.currentIndex() == 0: - handle = unicode(self.chumHandle.text()) + handle = str(self.chumHandle.text()) if not PesterProfile.checkLength(handle): self.errorMsg.setText("PROFILE HANDLE IS TOO LONG") return @@ -871,74 +846,69 @@ class PesterChooseProfile(QtGui.QDialog): @QtCore.pyqtSlot() def deleteProfile(self): if self.profileBox and self.profileBox.currentIndex() > 0: - handle = unicode(self.profileBox.currentText()) + handle = str(self.profileBox.currentText()) if handle == self.parent.profile().handle: - problem = QtGui.QMessageBox() + problem = QtWidgets.QMessageBox() # karxi Will probably change this to its own name later. problem.setObjectName("errmsg") problem.setStyleSheet(self.theme["main/defaultwindow/style"]) problem.setWindowTitle("Problem!") problem.setInformativeText("You can't delete the profile you're currently using!") - problem.setStandardButtons(QtGui.QMessageBox.Ok) + problem.setStandardButtons(QtWidgets.QMessageBox.Ok) problem.exec_() return # TODO: Make this select 'no' as the default, as usual. - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setStyleSheet(self.theme["main/defaultwindow/style"]) msgbox.setWindowTitle("WARNING!") msgbox.setInformativeText("Are you sure you want to delete the profile: %s" % (handle)) - msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) ret = msgbox.exec_() - if ret == QtGui.QMessageBox.Ok: + if ret == QtWidgets.QMessageBox.Ok: try: remove(_datadir+"profiles/%s.js" % (handle)) except OSError: - problem = QtGui.QMessageBox() + problem = QtWidgets.QMessageBox() problem.setObjectName("errmsg") problem.setStyleSheet(self.theme["main/defaultwindow/style"]) problem.setWindowTitle("Problem!") problem.setInformativeText("There was a problem deleting the profile: %s" % (handle)) - problem.setStandardButtons(QtGui.QMessageBox.Ok) + problem.setStandardButtons(QtWidgets.QMessageBox.Ok) problem.exec_() -class PesterMentions(QtGui.QDialog): +class PesterMentions(QtWidgets.QDialog): def __init__(self, window, theme, parent): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.setWindowTitle("Mentions") self.setModal(True) self.mainwindow = window self.theme = theme self.setStyleSheet(self.theme["main/defaultwindow/style"]) - self.mentionlist = QtGui.QListWidget(self) + self.mentionlist = QtWidgets.QListWidget(self) self.mentionlist.addItems(self.mainwindow.userprofile.getMentions()) - self.addBtn = QtGui.QPushButton("ADD MENTION", self) - self.connect(self.addBtn, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('addMention()')) + self.addBtn = QtWidgets.QPushButton("ADD MENTION", self) + self.addBtn.clicked.connect(self.addMention) - self.editBtn = QtGui.QPushButton("EDIT", self) - self.connect(self.editBtn, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('editSelected()')) - self.rmBtn = QtGui.QPushButton("REMOVE", self) - self.connect(self.rmBtn, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('removeCurrent()')) - layout_1 = QtGui.QHBoxLayout() + self.editBtn = QtWidgets.QPushButton("EDIT", self) + self.editBtn.clicked.connect(self.editSelected) + self.rmBtn = QtWidgets.QPushButton("REMOVE", self) + self.rmBtn.clicked.connect(self.removeCurrent) + layout_1 = QtWidgets.QHBoxLayout() layout_1.addWidget(self.editBtn) layout_1.addWidget(self.rmBtn) - self.ok = QtGui.QPushButton("OK", self) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('accept()')) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_2 = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.accept) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + layout_2 = QtWidgets.QHBoxLayout() layout_2.addWidget(self.cancel) layout_2.addWidget(self.ok) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.mentionlist) layout_0.addWidget(self.addBtn) layout_0.addLayout(layout_1) @@ -963,8 +933,8 @@ class PesterMentions(QtGui.QDialog): return try: re.compile(pdict["value"]) - except re.error, e: - quirkWarning = QtGui.QMessageBox(self) + except re.error as e: + quirkWarning = QtWidgets.QMessageBox(self) quirkWarning.setText("Not a valid regular expression!") quirkWarning.setInformativeText("H3R3S WHY DUMP4SS: %s" % (e)) quirkWarning.exec_() @@ -980,86 +950,80 @@ class PesterMentions(QtGui.QDialog): if i >= 0: self.mentionlist.takeItem(i) -class PesterOptions(QtGui.QDialog): +class PesterOptions(QtWidgets.QDialog): def __init__(self, config, theme, parent): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.setWindowTitle("Options") self.setModal(False) self.config = config self.theme = theme self.setStyleSheet(self.theme["main/defaultwindow/style"]) - layout_4 = QtGui.QVBoxLayout() + layout_4 = QtWidgets.QVBoxLayout() - hr = QtGui.QFrame() - hr.setFrameShape(QtGui.QFrame.HLine) - hr.setFrameShadow(QtGui.QFrame.Sunken) - vr = QtGui.QFrame() - vr.setFrameShape(QtGui.QFrame.VLine) - vr.setFrameShadow(QtGui.QFrame.Sunken) + hr = QtWidgets.QFrame() + hr.setFrameShape(QtWidgets.QFrame.HLine) + hr.setFrameShadow(QtWidgets.QFrame.Sunken) + vr = QtWidgets.QFrame() + vr.setFrameShape(QtWidgets.QFrame.VLine) + vr.setFrameShadow(QtWidgets.QFrame.Sunken) - self.tabs = QtGui.QButtonGroup(self) - self.connect(self.tabs, QtCore.SIGNAL('buttonClicked(int)'), - self, QtCore.SLOT('changePage(int)')) + self.tabs = QtWidgets.QButtonGroup(self) + self.tabs.buttonClicked[int].connect(self.changePage) tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Notifications", "Logging", "Idle/Updates", "Theme", "Connection"] if parent.advanced: tabNames.append("Advanced") for t in tabNames: - button = QtGui.QPushButton(t) + button = QtWidgets.QPushButton(t) self.tabs.addButton(button) layout_4.addWidget(button) button.setCheckable(True) self.tabs.button(-2).setChecked(True) - self.pages = QtGui.QStackedWidget(self) + self.pages = QtWidgets.QStackedWidget(self) - self.bandwidthcheck = QtGui.QCheckBox("Low Bandwidth", self) + self.bandwidthcheck = QtWidgets.QCheckBox("Low Bandwidth", self) if self.config.lowBandwidth(): self.bandwidthcheck.setChecked(True) - bandwidthLabel = QtGui.QLabel("(Stops you for receiving the flood of MOODS,\n" + bandwidthLabel = QtWidgets.QLabel("(Stops you for receiving the flood of MOODS,\n" " though stops chumlist from working properly)") font = bandwidthLabel.font() font.setPointSize(8) bandwidthLabel.setFont(font) - self.autonickserv = QtGui.QCheckBox("Auto-Identify with NickServ", self) + self.autonickserv = QtWidgets.QCheckBox("Auto-Identify with NickServ", self) self.autonickserv.setChecked(parent.userprofile.getAutoIdentify()) - self.connect(self.autonickserv, QtCore.SIGNAL('stateChanged(int)'), - self, QtCore.SLOT('autoNickServChange(int)')) - self.nickservpass = QtGui.QLineEdit(self) + self.autonickserv.stateChanged[int].connect(self.autoNickServChange) + self.nickservpass = QtWidgets.QLineEdit(self) self.nickservpass.setPlaceholderText("NickServ Password") - self.nickservpass.setEchoMode(QtGui.QLineEdit.PasswordEchoOnEdit) + self.nickservpass.setEchoMode(QtWidgets.QLineEdit.PasswordEchoOnEdit) self.nickservpass.setText(parent.userprofile.getNickServPass()) - self.autojoinlist = QtGui.QListWidget(self) + self.autojoinlist = QtWidgets.QListWidget(self) self.autojoinlist.addItems(parent.userprofile.getAutoJoins()) - self.addAutoJoinBtn = QtGui.QPushButton("Add", self) - self.connect(self.addAutoJoinBtn, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('addAutoJoin()')) - self.delAutoJoinBtn = QtGui.QPushButton("Remove", self) - self.connect(self.delAutoJoinBtn, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('delAutoJoin()')) + self.addAutoJoinBtn = QtWidgets.QPushButton("Add", self) + self.addAutoJoinBtn.clicked.connect(self.addAutoJoin) + self.delAutoJoinBtn = QtWidgets.QPushButton("Remove", self) + self.delAutoJoinBtn.clicked.connect(self.delAutoJoin) - self.tabcheck = QtGui.QCheckBox("Tabbed Conversations", self) + self.tabcheck = QtWidgets.QCheckBox("Tabbed Conversations", self) if self.config.tabs(): self.tabcheck.setChecked(True) - self.tabmemocheck = QtGui.QCheckBox("Tabbed Memos", self) + self.tabmemocheck = QtWidgets.QCheckBox("Tabbed Memos", self) if self.config.tabMemos(): self.tabmemocheck.setChecked(True) - self.hideOffline = QtGui.QCheckBox("Hide Offline Chums", self) + self.hideOffline = QtWidgets.QCheckBox("Hide Offline Chums", self) if self.config.hideOfflineChums(): self.hideOffline.setChecked(True) - self.soundcheck = QtGui.QCheckBox("Sounds On", self) - self.connect(self.soundcheck, QtCore.SIGNAL('stateChanged(int)'), - self, QtCore.SLOT('soundChange(int)')) - self.chatsoundcheck = QtGui.QCheckBox("Pester Sounds", self) + self.soundcheck = QtWidgets.QCheckBox("Sounds On", self) + self.soundcheck.stateChanged[int].connect(self.soundChange) + self.chatsoundcheck = QtWidgets.QCheckBox("Pester Sounds", self) self.chatsoundcheck.setChecked(self.config.chatSound()) - self.memosoundcheck = QtGui.QCheckBox("Memo Sounds", self) + self.memosoundcheck = QtWidgets.QCheckBox("Memo Sounds", self) self.memosoundcheck.setChecked(self.config.memoSound()) - self.connect(self.memosoundcheck, QtCore.SIGNAL('stateChanged(int)'), - self, QtCore.SLOT('memoSoundChange(int)')) - self.memopingcheck = QtGui.QCheckBox("Memo Ping", self) + self.memosoundcheck.stateChanged[int].connect(self.memoSoundChange) + self.memopingcheck = QtWidgets.QCheckBox("Memo Ping", self) self.memopingcheck.setChecked(self.config.memoPing()) - self.namesoundcheck = QtGui.QCheckBox("Memo Mention (initials)", self) + self.namesoundcheck = QtWidgets.QCheckBox("Memo Mention (initials)", self) self.namesoundcheck.setChecked(self.config.nameSound()) if self.config.soundOn(): self.soundcheck.setChecked(True) @@ -1070,63 +1034,60 @@ class PesterOptions(QtGui.QDialog): self.memosoundcheck.setEnabled(False) self.memoSoundChange(0) - self.editMentions = QtGui.QPushButton("Edit Mentions", self) - self.connect(self.editMentions, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('openMentions()')) - self.editMentions2 = QtGui.QPushButton("Edit Mentions", self) - self.connect(self.editMentions2, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('openMentions()')) + self.editMentions = QtWidgets.QPushButton("Edit Mentions", self) + self.editMentions.clicked.connect(self.openMentions) + self.editMentions2 = QtWidgets.QPushButton("Edit Mentions", self) + self.editMentions2.clicked.connect(self.openMentions) - self.volume = QtGui.QSlider(QtCore.Qt.Horizontal, self) + self.volume = QtWidgets.QSlider(QtCore.Qt.Horizontal, self) self.volume.setMinimum(0) self.volume.setMaximum(100) self.volume.setValue(self.config.volume()) - self.connect(self.volume, QtCore.SIGNAL('valueChanged(int)'), - self, QtCore.SLOT('printValue(int)')) + self.volume.valueChanged[int].connect(self.printValue) # Disable the volume slider if we can't actually use it. if parent.canSetVolume(): - self.currentVol = QtGui.QLabel( + self.currentVol = QtWidgets.QLabel( "{0!s}%".format(self.config.volume()), self) # We don't need to explicitly set this, but it helps drive the # point home self.volume.setEnabled(True) else: # We can't set the volume.... - self.currentVol = QtGui.QLabel( + self.currentVol = QtWidgets.QLabel( "(Disabled: Sound Mixer Error)", self) self.volume.setEnabled(False) self.currentVol.setAlignment(QtCore.Qt.AlignHCenter) - self.timestampcheck = QtGui.QCheckBox("Time Stamps", self) + self.timestampcheck = QtWidgets.QCheckBox("Time Stamps", self) if self.config.showTimeStamps(): self.timestampcheck.setChecked(True) - self.timestampBox = QtGui.QComboBox(self) + self.timestampBox = QtWidgets.QComboBox(self) self.timestampBox.addItem("12 hour") self.timestampBox.addItem("24 hour") if self.config.time12Format(): self.timestampBox.setCurrentIndex(0) else: self.timestampBox.setCurrentIndex(1) - self.secondscheck = QtGui.QCheckBox("Show Seconds", self) + self.secondscheck = QtWidgets.QCheckBox("Show Seconds", self) if self.config.showSeconds(): self.secondscheck.setChecked(True) - self.memomessagecheck = QtGui.QCheckBox("Show OP and Voice Messages in Memos", self) + self.memomessagecheck = QtWidgets.QCheckBox("Show OP and Voice Messages in Memos", self) if self.config.opvoiceMessages(): self.memomessagecheck.setChecked(True) if not ostools.isOSXBundle(): - self.animationscheck = QtGui.QCheckBox("Use animated smilies", self) + self.animationscheck = QtWidgets.QCheckBox("Use animated smilies", self) if self.config.animations(): self.animationscheck.setChecked(True) - animateLabel = QtGui.QLabel("(Disable if you leave chats open for LOOOONG periods of time)") + animateLabel = QtWidgets.QLabel("(Disable if you leave chats open for LOOOONG periods of time)") font = animateLabel.font() font.setPointSize(8) animateLabel.setFont(font) - self.userlinkscheck = QtGui.QCheckBox("Disable #Memo and @User Links", self) + self.userlinkscheck = QtWidgets.QCheckBox("Disable #Memo and @User Links", self) self.userlinkscheck.setChecked(self.config.disableUserLinks()) self.userlinkscheck.setVisible(False) @@ -1134,45 +1095,45 @@ class PesterOptions(QtGui.QDialog): # Will add ability to turn off groups later #self.groupscheck = QtGui.QCheckBox("Use Groups", self) #self.groupscheck.setChecked(self.config.useGroups()) - self.showemptycheck = QtGui.QCheckBox("Show Empty Groups", self) + self.showemptycheck = QtWidgets.QCheckBox("Show Empty Groups", self) self.showemptycheck.setChecked(self.config.showEmptyGroups()) - self.showonlinenumbers = QtGui.QCheckBox("Show Number of Online Chums", self) + self.showonlinenumbers = QtWidgets.QCheckBox("Show Number of Online Chums", self) self.showonlinenumbers.setChecked(self.config.showOnlineNumbers()) - sortLabel = QtGui.QLabel("Sort Chums") - self.sortBox = QtGui.QComboBox(self) + sortLabel = QtWidgets.QLabel("Sort Chums") + self.sortBox = QtWidgets.QComboBox(self) self.sortBox.addItem("Alphabetically") self.sortBox.addItem("By Mood") self.sortBox.addItem("Manually") method = self.config.sortMethod() if method >= 0 and method < self.sortBox.count(): self.sortBox.setCurrentIndex(method) - layout_3 = QtGui.QHBoxLayout() + layout_3 = QtWidgets.QHBoxLayout() layout_3.addWidget(sortLabel) layout_3.addWidget(self.sortBox, 10) - self.logpesterscheck = QtGui.QCheckBox("Log all Pesters", self) + self.logpesterscheck = QtWidgets.QCheckBox("Log all Pesters", self) if self.config.logPesters() & self.config.LOG: self.logpesterscheck.setChecked(True) - self.logmemoscheck = QtGui.QCheckBox("Log all Memos", self) + self.logmemoscheck = QtWidgets.QCheckBox("Log all Memos", self) if self.config.logMemos() & self.config.LOG: self.logmemoscheck.setChecked(True) - self.stamppestercheck = QtGui.QCheckBox("Log Time Stamps for Pesters", self) + self.stamppestercheck = QtWidgets.QCheckBox("Log Time Stamps for Pesters", self) if self.config.logPesters() & self.config.STAMP: self.stamppestercheck.setChecked(True) - self.stampmemocheck = QtGui.QCheckBox("Log Time Stamps for Memos", self) + self.stampmemocheck = QtWidgets.QCheckBox("Log Time Stamps for Memos", self) if self.config.logMemos() & self.config.STAMP: self.stampmemocheck.setChecked(True) - self.idleBox = QtGui.QSpinBox(self) + self.idleBox = QtWidgets.QSpinBox(self) self.idleBox.setStyleSheet("background:#FFFFFF") self.idleBox.setRange(1, 1440) self.idleBox.setValue(self.config.idleTime()) - layout_5 = QtGui.QHBoxLayout() - layout_5.addWidget(QtGui.QLabel("Minutes before Idle:")) + layout_5 = QtWidgets.QHBoxLayout() + layout_5.addWidget(QtWidgets.QLabel("Minutes before Idle:")) layout_5.addWidget(self.idleBox) - self.updateBox = QtGui.QComboBox(self) + self.updateBox = QtWidgets.QComboBox(self) self.updateBox.addItem("Once a Day") self.updateBox.addItem("Once a Week") self.updateBox.addItem("Only on Start") @@ -1180,59 +1141,57 @@ class PesterOptions(QtGui.QDialog): check = self.config.checkForUpdates() if check >= 0 and check < self.updateBox.count(): self.updateBox.setCurrentIndex(check) - layout_6 = QtGui.QHBoxLayout() - layout_6.addWidget(QtGui.QLabel("Check for\nPesterchum Updates:")) + layout_6 = QtWidgets.QHBoxLayout() + layout_6.addWidget(QtWidgets.QLabel("Check for\nPesterchum Updates:")) layout_6.addWidget(self.updateBox) if not ostools.isOSXLeopard(): - self.mspaCheck = QtGui.QCheckBox("Check for MSPA Updates", self) + self.mspaCheck = QtWidgets.QCheckBox("Check for MSPA Updates", self) self.mspaCheck.setChecked(self.config.checkMSPA()) - self.randomscheck = QtGui.QCheckBox("Receive Random Encounters") + self.randomscheck = QtWidgets.QCheckBox("Receive Random Encounters") self.randomscheck.setChecked(parent.userprofile.randoms) if not parent.randhandler.running: self.randomscheck.setEnabled(False) avail_themes = self.config.availableThemes() - self.themeBox = QtGui.QComboBox(self) + self.themeBox = QtWidgets.QComboBox(self) notheme = (theme.name not in avail_themes) for (i, t) in enumerate(avail_themes): self.themeBox.addItem(t) if (not notheme and t == theme.name) or (notheme and t == "pesterchum"): self.themeBox.setCurrentIndex(i) - self.refreshtheme = QtGui.QPushButton("Refresh current theme", self) - self.connect(self.refreshtheme, QtCore.SIGNAL('clicked()'), - parent, QtCore.SLOT('themeSelectOverride()')) - self.ghostchum = QtGui.QCheckBox("Pesterdunk Ghostchum!!", self) + self.refreshtheme = QtWidgets.QPushButton("Refresh current theme", self) + self.refreshtheme.clicked.connect(parent.themeSelectOverride) + self.ghostchum = QtWidgets.QCheckBox("Pesterdunk Ghostchum!!", self) self.ghostchum.setChecked(self.config.ghostchum()) self.buttonOptions = ["Minimize to Taskbar", "Minimize to Tray", "Quit"] - self.miniBox = QtGui.QComboBox(self) + self.miniBox = QtWidgets.QComboBox(self) self.miniBox.addItems(self.buttonOptions) self.miniBox.setCurrentIndex(self.config.minimizeAction()) - self.closeBox = QtGui.QComboBox(self) + self.closeBox = QtWidgets.QComboBox(self) self.closeBox.addItems(self.buttonOptions) self.closeBox.setCurrentIndex(self.config.closeAction()) - layout_mini = QtGui.QHBoxLayout() - layout_mini.addWidget(QtGui.QLabel("Minimize")) + layout_mini = QtWidgets.QHBoxLayout() + layout_mini.addWidget(QtWidgets.QLabel("Minimize")) layout_mini.addWidget(self.miniBox) - layout_close = QtGui.QHBoxLayout() - layout_close.addWidget(QtGui.QLabel("Close")) + layout_close = QtWidgets.QHBoxLayout() + layout_close.addWidget(QtWidgets.QLabel("Close")) layout_close.addWidget(self.closeBox) - self.pesterBlink = QtGui.QCheckBox("Blink Taskbar on Pesters", self) + self.pesterBlink = QtWidgets.QCheckBox("Blink Taskbar on Pesters", self) if self.config.blink() & self.config.PBLINK: self.pesterBlink.setChecked(True) - self.memoBlink = QtGui.QCheckBox("Blink Taskbar on Memos", self) + self.memoBlink = QtWidgets.QCheckBox("Blink Taskbar on Memos", self) if self.config.blink() & self.config.MBLINK: self.memoBlink.setChecked(True) - self.notifycheck = QtGui.QCheckBox("Toast Notifications", self) + self.notifycheck = QtWidgets.QCheckBox("Toast Notifications", self) if self.config.notify(): self.notifycheck.setChecked(True) - self.connect(self.notifycheck, QtCore.SIGNAL('stateChanged(int)'), - self, QtCore.SLOT('notifyChange(int)')) - self.notifyOptions = QtGui.QComboBox(self) + self.notifycheck.stateChanged[int].connect(self.notifyChange) + self.notifyOptions = QtWidgets.QComboBox(self) types = self.parent().tm.availableTypes() cur = self.parent().tm.currentType() self.notifyOptions.addItems(types) @@ -1240,49 +1199,47 @@ class PesterOptions(QtGui.QDialog): if t == cur: self.notifyOptions.setCurrentIndex(i) break - self.notifyTypeLabel = QtGui.QLabel("Type", self) - layout_type = QtGui.QHBoxLayout() + self.notifyTypeLabel = QtWidgets.QLabel("Type", self) + layout_type = QtWidgets.QHBoxLayout() layout_type.addWidget(self.notifyTypeLabel) layout_type.addWidget(self.notifyOptions) - self.notifySigninCheck = QtGui.QCheckBox("Chum signs in", self) + self.notifySigninCheck = QtWidgets.QCheckBox("Chum signs in", self) if self.config.notifyOptions() & self.config.SIGNIN: self.notifySigninCheck.setChecked(True) - self.notifySignoutCheck = QtGui.QCheckBox("Chum signs out", self) + self.notifySignoutCheck = QtWidgets.QCheckBox("Chum signs out", self) if self.config.notifyOptions() & self.config.SIGNOUT: self.notifySignoutCheck.setChecked(True) - self.notifyNewMsgCheck = QtGui.QCheckBox("New messages", self) + self.notifyNewMsgCheck = QtWidgets.QCheckBox("New messages", self) if self.config.notifyOptions() & self.config.NEWMSG: self.notifyNewMsgCheck.setChecked(True) - self.notifyNewConvoCheck = QtGui.QCheckBox("Only new conversations", self) + self.notifyNewConvoCheck = QtWidgets.QCheckBox("Only new conversations", self) if self.config.notifyOptions() & self.config.NEWCONVO: self.notifyNewConvoCheck.setChecked(True) - self.notifyMentionsCheck = QtGui.QCheckBox("Memo Mentions (initials)", self) + self.notifyMentionsCheck = QtWidgets.QCheckBox("Memo Mentions (initials)", self) if self.config.notifyOptions() & self.config.INITIALS: self.notifyMentionsCheck.setChecked(True) self.notifyChange(self.notifycheck.checkState()) if parent.advanced: # NOTE: This doesn't do anything right now - so change it! - self.modechange = QtGui.QLineEdit(self) - layout_change = QtGui.QHBoxLayout() - layout_change.addWidget(QtGui.QLabel("Change:")) + self.modechange = QtWidgets.QLineEdit(self) + layout_change = QtWidgets.QHBoxLayout() + layout_change.addWidget(QtWidgets.QLabel("Change:")) layout_change.addWidget(self.modechange) - self.ok = QtGui.QPushButton("OK", self) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('accept()')) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_2 = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.accept) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + layout_2 = QtWidgets.QHBoxLayout() layout_2.addWidget(self.cancel) layout_2.addWidget(self.ok) # Tab layouts # Chum List - widget = QtGui.QWidget() - layout_chumlist = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_chumlist = QtWidgets.QVBoxLayout(widget) layout_chumlist.setAlignment(QtCore.Qt.AlignTop) layout_chumlist.addWidget(self.hideOffline) #layout_chumlist.addWidget(self.groupscheck) @@ -1292,8 +1249,8 @@ class PesterOptions(QtGui.QDialog): self.pages.addWidget(widget) # Conversations - widget = QtGui.QWidget() - layout_chat = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_chat = QtWidgets.QVBoxLayout(widget) layout_chat.setAlignment(QtCore.Qt.AlignTop) layout_chat.addWidget(self.timestampcheck) layout_chat.addWidget(self.timestampBox) @@ -1310,8 +1267,8 @@ class PesterOptions(QtGui.QDialog): self.pages.addWidget(widget) # Interface - widget = QtGui.QWidget() - layout_interface = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_interface = QtWidgets.QVBoxLayout(widget) layout_interface.setAlignment(QtCore.Qt.AlignTop) layout_interface.addWidget(self.tabcheck) layout_interface.addWidget(self.tabmemocheck) @@ -1322,14 +1279,14 @@ class PesterOptions(QtGui.QDialog): self.pages.addWidget(widget) # Sound - widget = QtGui.QWidget() - layout_sound = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_sound = QtWidgets.QVBoxLayout(widget) layout_sound.setAlignment(QtCore.Qt.AlignTop) layout_sound.addWidget(self.soundcheck) - layout_indent = QtGui.QVBoxLayout() + layout_indent = QtWidgets.QVBoxLayout() layout_indent.addWidget(self.chatsoundcheck) layout_indent.addWidget(self.memosoundcheck) - layout_doubleindent = QtGui.QVBoxLayout() + layout_doubleindent = QtWidgets.QVBoxLayout() layout_doubleindent.addWidget(self.memopingcheck) layout_doubleindent.addWidget(self.namesoundcheck) layout_doubleindent.addWidget(self.editMentions) @@ -1338,7 +1295,7 @@ class PesterOptions(QtGui.QDialog): layout_indent.setContentsMargins(22,0,0,0) layout_sound.addLayout(layout_indent) layout_sound.addSpacing(15) - mvol = QtGui.QLabel("Master Volume:", self) + mvol = QtWidgets.QLabel("Master Volume:", self) # If we can't set the volume, grey this out as well #~mvol.setEnabled(parent.canSetVolume()) # Normally we'd grey this out, but that presently makes things @@ -1350,17 +1307,17 @@ class PesterOptions(QtGui.QDialog): self.pages.addWidget(widget) # Notifications - widget = QtGui.QWidget() - layout_notify = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_notify = QtWidgets.QVBoxLayout(widget) layout_notify.setAlignment(QtCore.Qt.AlignTop) layout_notify.addWidget(self.notifycheck) - layout_indent = QtGui.QVBoxLayout() + layout_indent = QtWidgets.QVBoxLayout() layout_indent.addLayout(layout_type) layout_indent.setContentsMargins(22,0,0,0) layout_indent.addWidget(self.notifySigninCheck) layout_indent.addWidget(self.notifySignoutCheck) layout_indent.addWidget(self.notifyNewMsgCheck) - layout_doubleindent = QtGui.QVBoxLayout() + layout_doubleindent = QtWidgets.QVBoxLayout() layout_doubleindent.addWidget(self.notifyNewConvoCheck) layout_doubleindent.setContentsMargins(22,0,0,0) layout_indent.addLayout(layout_doubleindent) @@ -1370,8 +1327,8 @@ class PesterOptions(QtGui.QDialog): self.pages.addWidget(widget) # Logging - widget = QtGui.QWidget() - layout_logs = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_logs = QtWidgets.QVBoxLayout(widget) layout_logs.setAlignment(QtCore.Qt.AlignTop) layout_logs.addWidget(self.logpesterscheck) layout_logs.addWidget(self.logmemoscheck) @@ -1380,8 +1337,8 @@ class PesterOptions(QtGui.QDialog): self.pages.addWidget(widget) # Idle/Updates - widget = QtGui.QWidget() - layout_idle = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_idle = QtWidgets.QVBoxLayout(widget) layout_idle.setAlignment(QtCore.Qt.AlignTop) layout_idle.addLayout(layout_5) layout_idle.addLayout(layout_6) @@ -1390,29 +1347,29 @@ class PesterOptions(QtGui.QDialog): self.pages.addWidget(widget) # Theme - widget = QtGui.QWidget() - layout_theme = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_theme = QtWidgets.QVBoxLayout(widget) layout_theme.setAlignment(QtCore.Qt.AlignTop) - layout_theme.addWidget(QtGui.QLabel("Pick a Theme:")) + layout_theme.addWidget(QtWidgets.QLabel("Pick a Theme:")) layout_theme.addWidget(self.themeBox) layout_theme.addWidget(self.refreshtheme) layout_theme.addWidget(self.ghostchum) self.pages.addWidget(widget) # Connection - widget = QtGui.QWidget() - layout_connect = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_connect = QtWidgets.QVBoxLayout(widget) layout_connect.setAlignment(QtCore.Qt.AlignTop) layout_connect.addWidget(self.bandwidthcheck) layout_connect.addWidget(bandwidthLabel) layout_connect.addWidget(self.autonickserv) - layout_indent = QtGui.QVBoxLayout() + layout_indent = QtWidgets.QVBoxLayout() layout_indent.addWidget(self.nickservpass) layout_indent.setContentsMargins(22,0,0,0) layout_connect.addLayout(layout_indent) - layout_connect.addWidget(QtGui.QLabel("Auto-Join Memos:")) + layout_connect.addWidget(QtWidgets.QLabel("Auto-Join Memos:")) layout_connect.addWidget(self.autojoinlist) - layout_8 = QtGui.QHBoxLayout() + layout_8 = QtWidgets.QHBoxLayout() layout_8.addWidget(self.addAutoJoinBtn) layout_8.addWidget(self.delAutoJoinBtn) layout_connect.addLayout(layout_8) @@ -1420,15 +1377,15 @@ class PesterOptions(QtGui.QDialog): # Advanced if parent.advanced: - widget = QtGui.QWidget() - layout_advanced = QtGui.QVBoxLayout(widget) + widget = QtWidgets.QWidget() + layout_advanced = QtWidgets.QVBoxLayout(widget) layout_advanced.setAlignment(QtCore.Qt.AlignTop) - layout_advanced.addWidget(QtGui.QLabel("Current User Mode: %s" % parent.modes)) + layout_advanced.addWidget(QtWidgets.QLabel("Current User Mode: %s" % parent.modes)) layout_advanced.addLayout(layout_change) self.pages.addWidget(widget) - layout_0 = QtGui.QVBoxLayout() - layout_1 = QtGui.QHBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() + layout_1 = QtWidgets.QHBoxLayout() layout_1.addLayout(layout_4) layout_1.addWidget(vr) layout_1.addWidget(self.pages) @@ -1519,10 +1476,8 @@ class PesterOptions(QtGui.QDialog): self.mentionmenu = None if not self.mentionmenu: self.mentionmenu = PesterMentions(self.parent(), self.theme, self) - self.connect(self.mentionmenu, QtCore.SIGNAL('accepted()'), - self, QtCore.SLOT('updateMentions()')) - self.connect(self.mentionmenu, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('closeMentions()')) + self.mentionmenu.accepted.connect(self.updateMentions) + self.mentionmenu.rejected.connect(self.closeMentions) self.mentionmenu.show() self.mentionmenu.raise_() self.mentionmenu.activateWindow() @@ -1538,9 +1493,9 @@ class PesterOptions(QtGui.QDialog): self.parent().userprofile.setMentions(m) self.mentionmenu = None -class PesterUserlist(QtGui.QDialog): +class PesterUserlist(QtWidgets.QDialog): def __init__(self, config, theme, parent): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.setModal(False) self.config = config self.theme = theme @@ -1548,31 +1503,28 @@ class PesterUserlist(QtGui.QDialog): self.setStyleSheet(self.theme["main/defaultwindow/style"]) self.resize(200, 600) - self.searchbox = QtGui.QLineEdit(self) + self.searchbox = QtWidgets.QLineEdit(self) #self.searchbox.setStyleSheet(theme["convo/input/style"]) # which style is better? self.searchbox.setPlaceholderText("Search") - self.connect(self.searchbox, QtCore.SIGNAL("textChanged(QString)"), self, QtCore.SLOT("updateUsers()")) + self.searchbox.textChanged['QString'].connect(self.updateUsers) - self.label = QtGui.QLabel("USERLIST") + self.label = QtWidgets.QLabel("USERLIST") self.userarea = RightClickList(self) self.userarea.setStyleSheet(self.theme["main/chums/style"]) - self.userarea.optionsMenu = QtGui.QMenu(self) + self.userarea.optionsMenu = QtWidgets.QMenu(self) - self.addChumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self) - self.connect(self.addChumAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('addChumSlot()')) - self.pesterChumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self) - self.connect(self.pesterChumAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('pesterChumSlot()')) + self.addChumAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self) + self.addChumAction.triggered.connect(self.addChumSlot) + self.pesterChumAction = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self) + self.pesterChumAction.triggered.connect(self.pesterChumSlot) self.userarea.optionsMenu.addAction(self.addChumAction) self.userarea.optionsMenu.addAction(self.pesterChumAction) - self.ok = QtGui.QPushButton("OK", self) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('accept()')) + self.ok.clicked.connect(self.accept) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.label) layout_0.addWidget(self.userarea) layout_0.addWidget(self.searchbox) @@ -1580,13 +1532,9 @@ class PesterUserlist(QtGui.QDialog): self.setLayout(layout_0) - self.connect(self.mainwindow, QtCore.SIGNAL('namesUpdated()'), - self, QtCore.SLOT('updateUsers()')) + self.mainwindow.namesUpdated.connect(self.updateUsers) - self.connect(self.mainwindow, - QtCore.SIGNAL('userPresentSignal(QString, QString, QString)'), - self, - QtCore.SLOT('updateUserPresent(QString, QString, QString)')) + self.mainwindow.userPresentSignal['QString', 'QString', 'QString'].connect(self.updateUserPresent) self.updateUsers() self.searchbox.setFocus() @@ -1596,14 +1544,14 @@ class PesterUserlist(QtGui.QDialog): self.userarea.clear() for n in names: if str(self.searchbox.text()) == "" or n.lower().find(str(self.searchbox.text()).lower()) != -1: - item = QtGui.QListWidgetItem(n) + item = QtWidgets.QListWidgetItem(n) item.setTextColor(QtGui.QColor(self.theme["main/chums/userlistcolor"])) self.userarea.addItem(item) self.userarea.sortItems() - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString, QString) def updateUserPresent(self, handle, channel, update): - h = unicode(handle) - c = unicode(channel) + h = str(handle) + c = str(channel) if update == "quit": self.delUser(h) elif update == "left" and c == "#pesterchum": @@ -1612,7 +1560,7 @@ class PesterUserlist(QtGui.QDialog): if str(self.searchbox.text()) == "" or h.lower().find(str(self.searchbox.text()).lower()) != -1: self.addUser(h) def addUser(self, name): - item = QtGui.QListWidgetItem(name) + item = QtWidgets.QListWidgetItem(name) item.setTextColor(QtGui.QColor(self.theme["main/chums/userlistcolor"])) self.userarea.addItem(item) self.userarea.sortItems() @@ -1642,13 +1590,13 @@ class PesterUserlist(QtGui.QDialog): return self.pesterChum.emit(cur.text()) - addChum = QtCore.pyqtSignal(QtCore.QString) - pesterChum = QtCore.pyqtSignal(QtCore.QString) + addChum = QtCore.pyqtSignal('QString') + pesterChum = QtCore.pyqtSignal('QString') -class MemoListItem(QtGui.QTreeWidgetItem): +class MemoListItem(QtWidgets.QTreeWidgetItem): def __init__(self, channel, usercount): - QtGui.QTreeWidgetItem.__init__(self, [channel, str(usercount)]) + QtWidgets.QTreeWidgetItem.__init__(self, [channel, str(usercount)]) self.target = channel def __lt__(self, other): column = self.treeWidget().sortColumn() @@ -1656,20 +1604,20 @@ class MemoListItem(QtGui.QTreeWidgetItem): return int(self.text(column)) < int(other.text(column)) return self.text(column) < other.text(column) -class PesterMemoList(QtGui.QDialog): +class PesterMemoList(QtWidgets.QDialog): def __init__(self, parent, channel=""): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.setModal(False) self.theme = parent.theme self.mainwindow = parent self.setStyleSheet(self.theme["main/defaultwindow/style"]) self.resize(460, 300) - self.label = QtGui.QLabel("MEMOS") + self.label = QtWidgets.QLabel("MEMOS") self.channelarea = RightClickTree(self) - self.channelarea.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) + self.channelarea.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.channelarea.setStyleSheet(self.theme["main/chums/style"]) - self.channelarea.optionsMenu = QtGui.QMenu(self) + self.channelarea.optionsMenu = QtWidgets.QMenu(self) self.channelarea.setColumnCount(2) self.channelarea.setHeaderLabels(["Memo", "Users"]) self.channelarea.setIndentation(0) @@ -1677,35 +1625,31 @@ class PesterMemoList(QtGui.QDialog): self.channelarea.setColumnWidth(1,10) self.channelarea.setSortingEnabled(True) self.channelarea.sortByColumn(0, QtCore.Qt.AscendingOrder) - self.connect(self.channelarea, - QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem *, int)'), - self, QtCore.SLOT('AcceptSelection()')) + self.channelarea.itemDoubleClicked[QTreeWidgetItem, int].connect(self.AcceptSelection) - self.orjoinlabel = QtGui.QLabel("OR MAKE A NEW MEMO:") - self.newmemo = QtGui.QLineEdit(channel, self) - self.secretChannel = QtGui.QCheckBox("HIDDEN CHANNEL?", self) - self.inviteChannel = QtGui.QCheckBox("INVITATION ONLY?", self) + self.orjoinlabel = QtWidgets.QLabel("OR MAKE A NEW MEMO:") + self.newmemo = QtWidgets.QLineEdit(channel, self) + self.secretChannel = QtWidgets.QCheckBox("HIDDEN CHANNEL?", self) + self.inviteChannel = QtWidgets.QCheckBox("INVITATION ONLY?", self) - self.timelabel = QtGui.QLabel("TIMEFRAME:") + self.timelabel = QtWidgets.QLabel("TIMEFRAME:") self.timeslider = TimeSlider(QtCore.Qt.Horizontal, self) self.timeinput = TimeInput(self.timeslider, self) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - self.join = QtGui.QPushButton("JOIN", self) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + self.join = QtWidgets.QPushButton("JOIN", self) self.join.setDefault(True) - self.connect(self.join, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('AcceptIfSelectionMade()')) - layout_ok = QtGui.QHBoxLayout() + self.join.clicked.connect(self.AcceptIfSelectionMade) + layout_ok = QtWidgets.QHBoxLayout() layout_ok.addWidget(self.cancel) layout_ok.addWidget(self.join) - layout_left = QtGui.QVBoxLayout() - layout_right = QtGui.QVBoxLayout() + layout_left = QtWidgets.QVBoxLayout() + layout_right = QtWidgets.QVBoxLayout() layout_right.setAlignment(QtCore.Qt.AlignTop) - layout_0 = QtGui.QVBoxLayout() - layout_1 = QtGui.QHBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() + layout_1 = QtWidgets.QHBoxLayout() layout_left.addWidget(self.label) layout_left.addWidget(self.channelarea) layout_right.addWidget(self.orjoinlabel) @@ -1756,27 +1700,27 @@ class PesterMemoList(QtGui.QDialog): self.accept() -class LoadingScreen(QtGui.QDialog): +class LoadingScreen(QtWidgets.QDialog): + tryAgain = QtCore.pyqtSignal() + def __init__(self, parent=None): - QtGui.QDialog.__init__(self, parent, (QtCore.Qt.CustomizeWindowHint | + QtWidgets.QDialog.__init__(self, parent, (QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint)) self.mainwindow = parent self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) - self.loadinglabel = QtGui.QLabel("CONN3CT1NG", self) - self.cancel = QtGui.QPushButton("QU1T >:?", self) - self.ok = QtGui.QPushButton("R3CONN3CT >:]", self) + self.loadinglabel = QtWidgets.QLabel("CONN3CT1NG", self) + self.cancel = QtWidgets.QPushButton("QU1T >:?", self) + self.ok = QtWidgets.QPushButton("R3CONN3CT >:]", self) # Help reduce the number of accidental Pesterchum closures... :| self.cancel.setAutoDefault(False) self.ok.setAutoDefault(True) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SIGNAL('tryAgain()')) + self.cancel.clicked.connect(self.reject) + self.ok.clicked.connect(self.tryAgain) - self.layout = QtGui.QVBoxLayout() + self.layout = QtWidgets.QVBoxLayout() self.layout.addWidget(self.loadinglabel) - layout_1 = QtGui.QHBoxLayout() + layout_1 = QtWidgets.QHBoxLayout() layout_1.addWidget(self.cancel) layout_1.addWidget(self.ok) self.layout.addLayout(layout_1) @@ -1807,14 +1751,14 @@ class LoadingScreen(QtGui.QDialog): tryAgain = QtCore.pyqtSignal() -class AboutPesterchum(QtGui.QDialog): +class AboutPesterchum(QtWidgets.QDialog): def __init__(self, parent=None): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.mainwindow = parent self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) - self.title = QtGui.QLabel("P3ST3RCHUM V. %s" % (_pcVersion)) - self.credits = QtGui.QLabel("Programming by:\n\ + self.title = QtWidgets.QLabel("P3ST3RCHUM V. %s" % (_pcVersion)) + self.credits = QtWidgets.QLabel("Programming by:\n\ illuminatedwax (ghostDunk)\n\ Kiooeht (evacipatedBox)\n\ Lexi (lexicalNuance)\n\ @@ -1833,39 +1777,36 @@ Special Thanks:\n\ gamblingGenocider\n\ Eco-Mono") - self.ok = QtGui.QPushButton("OK", self) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) + self.ok = QtWidgets.QPushButton("OK", self) + self.ok.clicked.connect(self.reject) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.title) layout_0.addWidget(self.credits) layout_0.addWidget(self.ok) self.setLayout(layout_0) -class UpdatePesterchum(QtGui.QDialog): +class UpdatePesterchum(QtWidgets.QDialog): def __init__(self, ver, url, parent=None): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.url = url self.mainwindow = parent self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) self.setWindowTitle("Pesterchum v%s Update" % (ver)) self.setModal(False) - self.title = QtGui.QLabel("An update to Pesterchum is available!") + self.title = QtWidgets.QLabel("An update to Pesterchum is available!") - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.title) - self.ok = QtGui.QPushButton("D0WNL04D 4ND 1NST4LL N0W", self) + self.ok = QtWidgets.QPushButton("D0WNL04D 4ND 1NST4LL N0W", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('accept()')) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_2 = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.accept) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + layout_2 = QtWidgets.QHBoxLayout() layout_2.addWidget(self.cancel) layout_2.addWidget(self.ok) @@ -1873,41 +1814,39 @@ class UpdatePesterchum(QtGui.QDialog): self.setLayout(layout_0) -class AddChumDialog(QtGui.QDialog): +class AddChumDialog(QtWidgets.QDialog): def __init__(self, avail_groups, parent=None): - QtGui.QDialog.__init__(self, parent) + QtWidgets.QDialog.__init__(self, parent) self.mainwindow = parent self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) self.setWindowTitle("Enter Chum Handle") self.setModal(True) - self.title = QtGui.QLabel("Enter Chum Handle") - self.chumBox = QtGui.QLineEdit(self) - self.groupBox = QtGui.QComboBox(self) + self.title = QtWidgets.QLabel("Enter Chum Handle") + self.chumBox = QtWidgets.QLineEdit(self) + self.groupBox = QtWidgets.QComboBox(self) avail_groups.sort() avail_groups.pop(avail_groups.index("Chums")) avail_groups.insert(0, "Chums") for g in avail_groups: self.groupBox.addItem(g) - self.newgrouplabel = QtGui.QLabel("Or make a new group:") - self.newgroup = QtGui.QLineEdit(self) + self.newgrouplabel = QtWidgets.QLabel("Or make a new group:") + self.newgroup = QtWidgets.QLineEdit(self) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.title) layout_0.addWidget(self.chumBox) layout_0.addWidget(self.groupBox) layout_0.addWidget(self.newgrouplabel) layout_0.addWidget(self.newgroup) - self.ok = QtGui.QPushButton("OK", self) + self.ok = QtWidgets.QPushButton("OK", self) self.ok.setDefault(True) - self.connect(self.ok, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('accept()')) - self.cancel = QtGui.QPushButton("CANCEL", self) - self.connect(self.cancel, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('reject()')) - layout_2 = QtGui.QHBoxLayout() + self.ok.clicked.connect(self.accept) + self.cancel = QtWidgets.QPushButton("CANCEL", self) + self.cancel.clicked.connect(self.reject) + layout_2 = QtWidgets.QHBoxLayout() layout_2.addWidget(self.cancel) layout_2.addWidget(self.ok) diff --git a/mispeller.py b/mispeller.py index b8240e3..5b1cb28 100644 --- a/mispeller.py +++ b/mispeller.py @@ -21,12 +21,12 @@ def mispeller(word): num = 1 else: num = random.choice([1,2]) - wordseq = range(0, len(word)) + wordseq = list(range(0, len(word))) random.shuffle(wordseq) letters = wordseq[0:num] def mistype(string, i): l = string[i] - if not kbdict.has_key(l): + if l not in kbdict: return string lpos = kbdict[l] newpos = lpos diff --git a/mood.py b/mood.py index 8c71f6d..993a7dc 100644 --- a/mood.py +++ b/mood.py @@ -1,4 +1,4 @@ -from PyQt4 import QtCore, QtGui +from PyQt5 import QtCore, QtGui, QtWidgets from generic import PesterIcon @@ -49,15 +49,13 @@ class PesterMoodHandler(QtCore.QObject): self.buttons[b.mood.value()] = b if b.mood.value() == self.mainwindow.profile().mood.value(): b.setSelected(True) - self.connect(b, QtCore.SIGNAL('clicked()'), - b, QtCore.SLOT('updateMood()')) - self.connect(b, QtCore.SIGNAL('moodUpdated(int)'), - self, QtCore.SLOT('updateMood(int)')) + b.clicked.connect(b.updateMood) + b.moodUpdated[int].connect(self.updateMood) def removeButtons(self): - for b in self.buttons.values(): + for b in list(self.buttons.values()): b.close() def showButtons(self): - for b in self.buttons.values(): + for b in list(self.buttons.values()): b.show() b.raise_() @QtCore.pyqtSlot(int) @@ -81,14 +79,14 @@ class PesterMoodHandler(QtCore.QObject): moodicon = newmood.icon(self.mainwindow.theme) self.mainwindow.currentMoodIcon.setPixmap(moodicon.pixmap(moodicon.realsize())) if oldmood.name() != newmood.name(): - for c in self.mainwindow.convos.values(): + for c in list(self.mainwindow.convos.values()): c.myUpdateMood(newmood) self.mainwindow.moodUpdated.emit() -class PesterMoodButton(QtGui.QPushButton): +class PesterMoodButton(QtWidgets.QPushButton): def __init__(self, parent, **options): icon = PesterIcon(options["icon"]) - QtGui.QPushButton.__init__(self, icon, options["text"], parent) + QtWidgets.QPushButton.__init__(self, icon, options["text"], parent) self.setIconSize(icon.realsize()) self.setFlat(True) self.resize(*options["size"]) diff --git a/ostools.py b/ostools.py index 3ee17ee..2602745 100644 --- a/ostools.py +++ b/ostools.py @@ -1,6 +1,7 @@ import os, sys import platform -from PyQt4.QtGui import QDesktopServices +from PyQt5.QtGui import QDesktopServices +from PyQt5.QtCore import QStandardPaths def isOSX(): return sys.platform == "darwin" @@ -32,10 +33,10 @@ def getDataDir(): # in the Pesterchum install directory (like before) try: if isOSX(): - return os.path.join(unicode(QDesktopServices.storageLocation(QDesktopServices.DataLocation)), "Pesterchum/") + return os.path.join(str(QStandardPaths.writableLocation(QStandardPaths.DataLocation)), "Pesterchum/") elif isLinux(): - return os.path.join(unicode(QDesktopServices.storageLocation(QDesktopServices.HomeLocation)), ".pesterchum/") + return os.path.join(str(QStandardPaths.writableLocation(QStandardPaths.HomeLocation)), ".pesterchum/") else: - return os.path.join(unicode(QDesktopServices.storageLocation(QDesktopServices.DataLocation)), "pesterchum/") + return os.path.join(str(QStandardPaths.writableLocation(QStandardPaths.DataLocation)), "pesterchum/") except UnicodeDecodeError: return '' diff --git a/oyoyo/client.py b/oyoyo/client.py index 41f0ae1..b5c819a 100644 --- a/oyoyo/client.py +++ b/oyoyo/client.py @@ -127,7 +127,7 @@ class IRCClient: logging.info('---> send "%s"' % msg) try: self.socket.send(msg + bytes("\r\n", "ascii")) - except socket.error, se: + except socket.error as se: try: # a little dance of compatibility to get the errno errno = se.errno except AttributeError: @@ -160,12 +160,12 @@ class IRCClient: while not self._end: try: buffer += self.socket.recv(1024) - except socket.timeout, e: + except socket.timeout as e: if self._end: break logging.debug("timeout in client.py") raise e - except socket.error, e: + except socket.error as e: if self._end: break logging.debug("error %s" % e) @@ -195,10 +195,10 @@ class IRCClient: pass yield True - except socket.timeout, se: + except socket.timeout as se: logging.debug("passing timeout") raise se - except socket.error, se: + except socket.error as se: logging.debug("problem: %s" % (se)) if self.socket: logging.info('error: closing socket') @@ -264,12 +264,12 @@ class IRCApp: while self.running: found_one_alive = False - for client, clientdesc in self._clients.iteritems(): + for client, clientdesc in self._clients.items(): if clientdesc.con is None: clientdesc.con = client.connect() try: - clientdesc.con.next() + next(clientdesc.con) except Exception as e: logging.error('client error %s' % e) logging.error(traceback.format_exc()) diff --git a/oyoyo/examplebot.py b/oyoyo/examplebot.py index 81aac02..dfd1885 100644 --- a/oyoyo/examplebot.py +++ b/oyoyo/examplebot.py @@ -21,7 +21,7 @@ class MyHandler(DefaultCommandHandler): match = re.match('\!say (.*)', msg) if match: to_say = match.group(1).strip() - print('Saying, "%s"' % to_say) + print(('Saying, "%s"' % to_say)) helpers.msg(self.client, chan, to_say) @@ -37,7 +37,7 @@ def main(): conn = cli.connect() while True: - conn.next() ## python 2 + next(conn) ## python 2 # next(conn) ## python 3 diff --git a/oyoyo/helpers.py b/oyoyo/helpers.py index c82ec9c..5c25b59 100644 --- a/oyoyo/helpers.py +++ b/oyoyo/helpers.py @@ -111,7 +111,7 @@ def _addNumerics(): cli.send(cmd_num, *args) return f m = sys.modules[__name__] - for num, name in ircevents.numeric_events.iteritems(): + for num, name in ircevents.numeric_events.items(): setattr(m, name, numericcmd(num, name)) _addNumerics() diff --git a/oyoyo/ircevents.py b/oyoyo/ircevents.py index 6d8969b..11a8583 100644 --- a/oyoyo/ircevents.py +++ b/oyoyo/ircevents.py @@ -206,5 +206,5 @@ protocol_events = [ "pong", ] -all_events = generated_events + protocol_events + numeric_events.values() +all_events = generated_events + protocol_events + list(numeric_events.values()) diff --git a/oyoyo/services.py b/oyoyo/services.py index 9183beb..751a787 100644 --- a/oyoyo/services.py +++ b/oyoyo/services.py @@ -1,5 +1,5 @@ import sys -from helpers import msg +from .helpers import msg # NickServ basic functions _nickservfuncs = ( @@ -103,7 +103,7 @@ def _addServ(serv, funcs, prefix=""): if prefix: cmd_name = prefix.upper() + " " + cmd_name def f(cli, *args): - print cmd_name, " ".join(args) + print(cmd_name, " ".join(args)) #cli.send(cmd_name, serv.name, *args) return f for t in funcs: diff --git a/parsetools.py b/parsetools.py index 25bf3f9..509dedb 100644 --- a/parsetools.py +++ b/parsetools.py @@ -4,7 +4,7 @@ import ostools import collections from copy import copy from datetime import timedelta -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets from generic import mysteryTime from quirks import ScriptQuirks @@ -17,6 +17,12 @@ import pnc.lexercon as lexercon # I'll clean up the things that are no longer needed once the transition is # actually finished. +try: + QString = unicode +except NameError: + # Python 3 + QString = str + _ctag_begin = re.compile(r'(?i)') _gtag_begin = re.compile(r'(?i)') _ctag_end = re.compile(r'(?i)') @@ -36,7 +42,7 @@ quirkloader = ScriptQuirks() quirkloader.add(PythonQuirks()) quirkloader.add(LuaQuirks()) quirkloader.loadAll() -print quirkloader.funcre() +print(quirkloader.funcre()) _functionre = re.compile(r"%s" % quirkloader.funcre()) _groupre = re.compile(r"\\([0-9]+)") @@ -51,7 +57,7 @@ def lexer(string, objlist): for (oType, regexp) in objlist: newstringlist = [] for (stri, s) in enumerate(stringlist): - if type(s) not in [str, unicode]: + if type(s) not in [str, str]: newstringlist.append(s) continue lasti = 0 @@ -220,7 +226,7 @@ kxpclexer = lexercon.Pesterchum() def kxlexMsg(string): # Do a bit of sanitization. - msg = unicode(string) + msg = str(string) # TODO: Let people paste line-by-line normally. Maybe have a mass-paste # right-click option? msg = msg.replace('\n', ' ').replace('\r', ' ') @@ -247,9 +253,9 @@ def lexMessage(string): (smiley, _smilere), (honker, _honk)] - string = unicode(string) + string = str(string) string = string.replace("\n", " ").replace("\r", " ") - lexed = lexer(unicode(string), lexlist) + lexed = lexer(str(string), lexlist) balanced = [] beginc = 0 @@ -271,7 +277,7 @@ def lexMessage(string): balanced.append(colorEnd("")) if len(balanced) == 0: balanced.append("") - if type(balanced[len(balanced)-1]) not in [str, unicode]: + if type(balanced[len(balanced)-1]) not in [str, str]: balanced.append("") return balanced @@ -279,12 +285,12 @@ def convertTags(lexed, format="html"): if format not in ["html", "bbcode", "ctag", "text"]: raise ValueError("Color format not recognized") - if type(lexed) in [str, unicode]: + if type(lexed) in [str, str]: lexed = lexMessage(lexed) escaped = "" firststr = True for (i, o) in enumerate(lexed): - if type(o) in [str, unicode]: + if type(o) in [str, str]: if format == "html": escaped += o.replace("&", "&").replace(">", ">").replace("<","<") else: @@ -392,7 +398,7 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False): while len(lexed) > 0: rounds += 1 if debug: - print "[Starting round {}...]".format(rounds) + print("[Starting round {}...]".format(rounds)) msg = lexed.popleft() msglen = 0 is_text = False @@ -433,9 +439,9 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False): # instead? subround += 1 if debug: - print "[Splitting round {}-{}...]".format( + print("[Splitting round {}-{}...]".format( rounds, subround - ) + )) point = msg.rfind(' ', 0, lenl) if point < 0: # No spaces to break on...ugh. Break at the last space @@ -448,12 +454,12 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False): # Remove what we just added. msg = msg[point:] if debug: - print "msg = {!r}".format(msg) + print("msg = {!r}".format(msg)) else: # Catch the remainder. stack.append(msg) if debug: - print "msg caught; stack = {!r}".format(stack) + print("msg caught; stack = {!r}".format(stack)) # Done processing. Pluck out the first portion so we can # continue processing, clean it up a bit, then add the rest to # our waiting list. @@ -494,16 +500,16 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False): cte = lexercon.CTagEnd("", fmt, None) working.extend([cte] * len(open_ctags)) if debug: - print "\tRound {0} linebreak: Added {1} closing ctags".format( + print("\tRound {0} linebreak: Added {1} closing ctags".format( rounds, len(open_ctags) - ) + )) # Run it through the lexer again to render it. - working = u''.join(kxpclexer.list_convert(working)) + working = ''.join(kxpclexer.list_convert(working)) if debug: - print "\tRound {0} add: len == {1} (of {2})".format( + print("\tRound {0} add: len == {1} (of {2})".format( rounds, len(working), maxlen - ) + )) # Now that it's done the work for us, append and resume. output.append(working) @@ -518,7 +524,7 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False): # We have more to go. # Reset working, starting it with the unclosed ctags. if debug: - print "\tRound {0}: More to lex".format(rounds) + print("\tRound {0}: More to lex".format(rounds)) working = open_ctags[:] # Calculate the length of the starting tags, add it before # anything else. @@ -533,7 +539,7 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False): if debug or True: # This probably shouldn't happen, and if it does, I want to # know if it *works* properly. - print "\tRound {0}: No more to lex".format(rounds) + print("\tRound {0}: No more to lex".format(rounds)) # Clean up, just in case. working = [] open_ctags = [] @@ -582,8 +588,8 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False): working = kxpclexer.list_convert(working) if len(working) > 0: if debug: - print "Adding end trails: {!r}".format(working) - working = u''.join(working) + print("Adding end trails: {!r}".format(working)) + working = ''.join(working) output.append(working) # We're...done? @@ -596,7 +602,7 @@ def splitMessage(msg, format="ctag"): # split long text lines buf = [] for o in msg: - if type(o) in [str, unicode] and len(o) > 200: + if type(o) in [str, str] and len(o) > 200: # Split with a step of 200. I.e., cut long segments into chunks of # 200 characters. # I'm...not sure why this is done. I'll probably factor it out @@ -614,7 +620,7 @@ def splitMessage(msg, format="ctag"): cbegintags = [] # This is the final result. output = [] - print repr(msg) + print(repr(msg)) for o in msg: oldctag = None # Add to the working segment. @@ -687,9 +693,7 @@ def _is_ooc(msg, strict=True): # We have a match.... ooc1, ooc2 = oocDetected.group(1, 2) # Make sure the appropriate braces are used. - mbraces = map( - lambda br: ooc1 == br[0] and ooc2 == br[1], - braces) + mbraces = [ooc1 == br[0] and ooc2 == br[1] for br in braces] if any(mbraces): # If any of those passes matched, we're good to go; it's OOC. return True @@ -711,7 +715,7 @@ def kxhandleInput(ctx, text=None, flavor=None): if text is None: # Fetch the raw text from the input box. text = ctx.textInput.text() - text = unicode(ctx.textInput.text()) + text = str(ctx.textInput.text()) # Preprocessing stuff. msg = text.strip() @@ -731,7 +735,7 @@ def kxhandleInput(ctx, text=None, flavor=None): # Determine if the line actually *is* OOC. if is_ooc and not oocDetected: # If we're supposed to be OOC, apply it artificially. - msg = u"(( {} ))".format(msg) + msg = "(( {} ))".format(msg) # Also, quirk stuff. should_quirk = ctx.applyquirks else: @@ -764,7 +768,7 @@ def kxhandleInput(ctx, text=None, flavor=None): except Exception as err: # Tell the user we couldn't do quirk things. # TODO: Include the actual error...and the quirk it came from? - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setText("Whoa there! There seems to be a problem.") err_info = "A quirk seems to be having a problem. (Error: {!s})" err_info = err_info.format(err) @@ -776,9 +780,9 @@ def kxhandleInput(ctx, text=None, flavor=None): try: # Turns out that Windows consoles can't handle unicode, heh...who'da # thunk. We have to repr() this, as such. - print repr(msg) + print(repr(msg)) except Exception as err: - print "(Couldn't print processed message: {!s})".format(err) + print("(Couldn't print processed message: {!s})".format(err)) # karxi: We have a list...but I'm not sure if we ever get anything else, so # best to play it safe. I may remove this during later refactoring. @@ -790,26 +794,23 @@ def kxhandleInput(ctx, text=None, flavor=None): # an object type I provided - just so I could pluck them out # later. msg[i] = m.convert(format="ctag") - msg = u''.join(msg) + msg = ''.join(msg) # Quirks have been applied. Lex the messages (finally). msg = kxlexMsg(msg) # Debug output. try: - print repr(msg) + print(repr(msg)) except Exception as err: - print "(Couldn't print lexed message: {!s})".format(err) + print("(Couldn't print lexed message: {!s})".format(err)) # Remove coloring if this is a /me! if is_action: # Filter out formatting specifiers (just ctags, at the moment). - msg = filter( - lambda m: not isinstance(m, + msg = [m for m in msg if not isinstance(m, (lexercon.CTag, lexercon.CTagEnd) - ), - msg - ) + )] # We'll also add /me to the beginning of any new messages, later. # Put what's necessary in before splitting. @@ -850,7 +851,7 @@ def kxhandleInput(ctx, text=None, flavor=None): # if ceased, rebegin if hasattr(ctx, 'chumopen') and not ctx.chumopen: ctx.mainwindow.newConvoStarted.emit( - QtCore.QString(ctx.title()), True + QString(ctx.title()), True ) ctx.setChumOpen(True) @@ -859,7 +860,7 @@ def kxhandleInput(ctx, text=None, flavor=None): # If we're working with an action and we split, it should have /mes. if is_action and i > 0: # Add them post-split. - lm = u"/me " + lm + lm = "/me " + lm # NOTE: No reason to reassign for now, but...why not? lexmsgs[i] = lm @@ -876,11 +877,11 @@ def kxhandleInput(ctx, text=None, flavor=None): # We fetched the information outside of the loop, so just # construct the messages. - clientMsg = u"{2}{3}{4}: {0}".format( + clientMsg = "{2}{3}{4}: {0}".format( clientMsg, colorcmd, grammar.pcf, initials, grammar.number ) # Not sure if this needs a space at the end...? - serverMsg = u"{2}: {0}".format( + serverMsg = "{2}: {0}".format( serverMsg, colorcmd, initials) ctx.addMessage(clientMsg, True) @@ -984,7 +985,7 @@ def parseRegexpFunctions(to): backr = _groupre.search(mo.group()) if backr is not None: current.append(backreference(backr.group(1))) - elif mo.group()[:-1] in functiondict.keys(): + elif mo.group()[:-1] in list(functiondict.keys()): p = parseLeaf(functiondict[mo.group()[:-1]], current) current.append(p) current = p @@ -1001,7 +1002,7 @@ def parseRegexpFunctions(to): def img2smiley(string): - string = unicode(string) + string = str(string) def imagerep(mo): return reverse_smiley[mo.group(1)] string = re.sub(r'', imagerep, string) @@ -1082,8 +1083,8 @@ if ostools.isOSXBundle(): -reverse_smiley = dict((v,k) for k, v in smiledict.iteritems()) -_smilere = re.compile("|".join(smiledict.keys())) +reverse_smiley = dict((v,k) for k, v in smiledict.items()) +_smilere = re.compile("|".join(list(smiledict.keys()))) class ThemeException(Exception): def __init__(self, value): diff --git a/pesterchum b/pesterchum deleted file mode 100755 index a206116..0000000 --- a/pesterchum +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd `dirname $0` -python2 pesterchum.py $@ diff --git a/pesterchum-update-from3.14.nsi b/pesterchum-update-from3.14.nsi deleted file mode 100644 index 1dac4b0..0000000 --- a/pesterchum-update-from3.14.nsi +++ /dev/null @@ -1,104 +0,0 @@ - -; The name of the installer -Name "PESTERCHUM3.14 to 3.41" - -; The file to write -OutFile "pesterchum3.14to3.41.exe" - -RequestExecutionLevel admin - -Page components -Page instfiles - -UninstPage uninstConfirm -UninstPage instfiles - -; The stuff to install -Section "Pesterchum" - - SectionIn RO - - ReadRegStr $INSTDIR HKLM "SOFTWARE\Pesterchum" "Install_Dir" - - StrCmp $INSTDIR "" error - - ; Set output path to the installation directory. - SetOutPath $INSTDIR - - ; Check and see if this is really 3.14 - IfFileExists library.zip 0 error - - ClearErrors - CreateDirectory $TEMP\pesterchum_backup - IfErrors backuperror 0 - CopyFiles $INSTDIR\pesterchum.js $TEMP\pesterchum_backup - CopyFiles $INSTDIR\profiles $TEMP\pesterchum_backup - CopyFiles $INSTDIR\logs $TEMP\pesterchum_backup - IfErrors cantcopy 0 - - Delete $INSTDIR\uninstall.exe - - ; Remove shortcuts, if any - Delete "$SMPROGRAMS\Pesterchum\*.*" - - ; Remove directories used - RMDir "$SMPROGRAMS\Pesterchum" - RMDir /r "$INSTDIR" - - ; Put file there - File /r *.* - Rename $INSTDIR\README.mkdn $INSTDIR\readme.txt - Rename $INSTDIR\CHANGELOG.mkdn $INSTDIR\changelog.txt - - ; Copy backup files - ClearErrors - CopyFiles $TEMP\pesterchum_backup\*.* $INSTDIR - IfErrors brokeinstall 0 - RMDIR /r "$TEMP\pesterchum_backup" - - WriteUninstaller "uninstall.exe" - - CreateDirectory "$SMPROGRAMS\Pesterchum" - CreateShortcut "$SMPROGRAMS\Pesterchum\Pesterchum.lnk" "$INSTDIR\pesterchum.exe" - CreateShortcut "$DESKTOP\Pesterchum.lnk" "$INSTDIR\pesterchum.exe" - CreateShortcut "$SMPROGRAMS\Pesterchum\Readme.lnk" "$INSTDIR\readme.txt" - CreateShortcut "$SMPROGRAMS\Pesterchum\Uninstall.lnk" "$INSTDIR\uninstall.exe" - CreateShortcut "$SMPROGRAMS\Pesterchum\Logs.lnk" "$LOCALAPPDATA\pesterchum\logs" - - Goto done - - error: - MessageBox MB_OK "Pesterchum 3.14 (or 3.41 beta) not found on this machine!" - Goto done - backuperror: - IfFileExists $TEMP\pesterchum_backup brokeinstall cantmaketmp - cantmaketmp: - MessageBox MB_OK "Error! Can't make temporary directory (to save your files) for some raisin. Check your privileges?? i dunno tbqh, soryr *sorry" - Goto done - brokeinstall: - MessageBox MB_OK "Broken install detected. Please copy the files in $TEMP\pesterchum_backup to some place safe and then delete that folder." - Goto done - cantcopy: - MessageBox MB_OK "Can't seem to copy Pesterchum backup files to temp directory." - Goto done - done: - -SectionEnd - -Section "Uninstall" - - ; Remove registry keys - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pesterchum" - DeleteRegKey HKLM SOFTWARE\Pesterchum - - ; Remove files and uninstaller - Delete $INSTDIR\uninstall.exe - - ; Remove shortcuts, if any - Delete "$SMPROGRAMS\Pesterchum\*.*" - - ; Remove directories used - RMDir "$SMPROGRAMS\Pesterchum" - RMDir /r "$INSTDIR" - -SectionEnd \ No newline at end of file diff --git a/pesterchum-update.nsi b/pesterchum-update.nsi deleted file mode 100644 index 39a8294..0000000 --- a/pesterchum-update.nsi +++ /dev/null @@ -1,47 +0,0 @@ - -; The name of the installer -Name "PESTERCHUM3.41" - -; The file to write -OutFile "pesterchum3.41.update.exe" - -RequestExecutionLevel admin - -Page components -Page instfiles - -; The stuff to install -Section "Pesterchum" - - SectionIn RO - - ReadRegStr $INSTDIR HKLM "SOFTWARE\Pesterchum" "Install_Dir" - - StrCmp $INSTDIR "" error - - ; Set output path to the installation directory. - SetOutPath $INSTDIR - - ; Put file there - File /r themes - File /r smilies - File /r quirks - File README.mkdn - File CHANGELOG.mkdn - File version.py - File pesterchum.exe - File pesterchum.exe.manifest - - - Rename $INSTDIR\README.mkdn $INSTDIR\readme.txt - Rename $INSTDIR\CHANGELOG.mkdn $INSTDIR\changelog.txt - - Delete "$SMPROGRAMS\Pesterchum\Pesterchum.lnk" - CreateShortcut "$SMPROGRAMS\Pesterchum\Pesterchum.lnk" "$INSTDIR\pesterchum.exe" - - Goto done - error: - MessageBox MB_OK "Pesterchum not found on this machine!" - done: - -SectionEnd diff --git a/pesterchum.cfg b/pesterchum.cfg deleted file mode 100644 index 7763cfe..0000000 --- a/pesterchum.cfg +++ /dev/null @@ -1,32 +0,0 @@ -#PESTERCHUM CONFIG V2.5 -debug: false -notify: false -tray: true -claf: false -handle: elegantDiversion -mood: 0 -color: -15420406 -skin: trollian -#CHUMROLL BEGIN -handle: adiosToreador -color: -5614336 -handle: arachnidsGrip -color: -6206085 -#CHUMROLL END -#QUIRKS BEGIN -search: [p|P] -replace: 9 -search: [Z|z] -replace: 2 -search: [S|s] -replace: 5 -search: [O|o] -replace: 0 -search: [L|l] -replace: | -prefix: ==> -suffix: -#QUIRKS END -#TROLLS BEGIN -#TROLLS END -#EOF diff --git a/pesterchum.ico b/pesterchum.ico deleted file mode 100644 index 5b8fa1c..0000000 Binary files a/pesterchum.ico and /dev/null differ diff --git a/pesterchum.nsi b/pesterchum.nsi deleted file mode 100644 index d8992a9..0000000 --- a/pesterchum.nsi +++ /dev/null @@ -1,69 +0,0 @@ - -; The name of the installer -Name "PESTERCHUM3.41" - -; The file to write -OutFile "pesterchum3.41.exe" - -InstallDir C:\Pesterchum - -InstallDirRegKey HKLM "Software\Pesterchum" "Install_Dir" -RequestExecutionLevel admin - -Page components -Page directory -Page instfiles - -UninstPage uninstConfirm -UninstPage instfiles - - -; The stuff to install -Section "Pesterchum" - - SectionIn RO - - ; Set output path to the installation directory. - SetOutPath $INSTDIR - - ; Put file there - File /r *.* - Rename $INSTDIR\README.mkdn $INSTDIR\readme.txt - Rename $INSTDIR\CHANGELOG.mkdn $INSTDIR\changelog.txt - - ; Write the installation path into the registry - WriteRegStr HKLM SOFTWARE\Pesterchum "Install_Dir" "$INSTDIR" - - ; Write the uninstall keys for Windows - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pesterchum" "DisplayName" "PESTERCHUM" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pesterchum" "UninstallString" '"$INSTDIR\uninstall.exe"' - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pesterchum" "NoModify" 1 - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pesterchum" "NoRepair" 1 - WriteUninstaller "uninstall.exe" - - CreateDirectory "$SMPROGRAMS\Pesterchum" - CreateShortcut "$SMPROGRAMS\Pesterchum\Pesterchum.lnk" "$INSTDIR\pesterchum.exe" - CreateShortcut "$DESKTOP\Pesterchum.lnk" "$INSTDIR\pesterchum.exe" - CreateShortcut "$SMPROGRAMS\Pesterchum\Readme.lnk" "$INSTDIR\readme.txt" - CreateShortcut "$SMPROGRAMS\Pesterchum\Uninstall.lnk" "$INSTDIR\uninstall.exe" - - CreateShortcut "$SMPROGRAMS\Pesterchum\Logs.lnk" "$LOCALAPPDATA\pesterchum\logs" -SectionEnd - -Section "Uninstall" - - ; Remove registry keys - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pesterchum" - DeleteRegKey HKLM SOFTWARE\Pesterchum - - ; Remove files and uninstaller - Delete $INSTDIR\uninstall.exe - - ; Remove shortcuts, if any - Delete "$SMPROGRAMS\Pesterchum\*.*" - - ; Remove directories used - RMDir "$SMPROGRAMS\Pesterchum" - RMDir /r "$INSTDIR" - -SectionEnd diff --git a/pesterchum.py b/pesterchum.py index e1d709a..36bf868 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -1,5 +1,11 @@ # pesterchum import os, shutil, sys, getopt +try: + QString = unicode +except NameError: + # Python 3 + QString = str + if os.path.dirname(sys.argv[0]): os.chdir(os.path.dirname(sys.argv[0])) import logging @@ -12,7 +18,7 @@ from datetime import * import random import re from time import time -import threading, Queue +import threading, queue try: import json except: @@ -39,13 +45,13 @@ else: reqmissing = [] optmissing = [] try: - from PyQt4 import QtGui, QtCore + from PyQt5 import QtCore, QtGui, QtMultimedia, QtWidgets except ImportError as e: module = str(e) if module.startswith("No module named ") or \ module.startswith("cannot import name "): reqmissing.append(module[module.rfind(" ")+1:]) - else: print e + else: print(e) del module try: import pygame @@ -53,12 +59,13 @@ except ImportError as e: pygame = None module = str(e) if module[:16] == "No module named ": optmissing.append(module[16:]) - else: print e + else: print(e) del module if reqmissing: - print "ERROR: The following modules are required for Pesterchum to run and are missing on your system:" - for m in reqmissing: print "* "+m - exit() + print("ERROR: The following modules are required for Pesterchum to run and are missing on your system:") + for m in reqmissing: print("* "+m) + # False flag for some reason. + #exit() vnum = QtCore.qVersion() major = int(vnum[:vnum.find(".")]) if vnum.find(".", vnum.find(".")+1) != -1: @@ -66,8 +73,8 @@ if vnum.find(".", vnum.find(".")+1) != -1: else: minor = int(vnum[vnum.find(".")+1:]) if not ((major > 4) or (major == 4 and minor >= 6)): - print "ERROR: Pesterchum requires Qt version >= 4.6" - print "You currently have version " + vnum + ". Please upgrade Qt." + print("ERROR: Pesterchum requires Qt version >= 4.6") + print("You currently have version " + vnum + ". Please upgrade Qt.") exit() import ostools @@ -143,7 +150,7 @@ class waitingMessageHolder(object): def __init__(self, mainwindow, **msgfuncs): self.mainwindow = mainwindow self.funcs = msgfuncs - self.queue = msgfuncs.keys() + self.queue = list(msgfuncs.keys()) if len(self.queue) > 0: self.mainwindow.updateSystemTray() def waitingHandles(self): @@ -159,7 +166,7 @@ class waitingMessageHolder(object): if len(self.queue) == 0: self.mainwindow.updateSystemTray() def addMessage(self, handle, func): - if not self.funcs.has_key(handle): + if handle not in self.funcs: self.queue.append(handle) self.funcs[handle] = func if len(self.queue) > 0: @@ -167,7 +174,7 @@ class waitingMessageHolder(object): def __len__(self): return len(self.queue) -class chumListing(QtGui.QTreeWidgetItem): +class chumListing(QtWidgets.QTreeWidgetItem): def __init__(self, chum, window): super(chumListing, self).__init__([chum.handle]) self.mainwindow = window @@ -264,43 +271,34 @@ class chumArea(RightClickTree): self.showAllChums() if not self.mainwindow.config.showEmptyGroups(): self.hideEmptyGroups() - self.groupMenu = QtGui.QMenu(self) - self.canonMenu = QtGui.QMenu(self) - self.optionsMenu = QtGui.QMenu(self) - self.pester = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self) - self.connect(self.pester, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('activateChum()')) - self.removechum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/removechum"], self) - self.connect(self.removechum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('removeChum()')) - self.blockchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"], self) - self.connect(self.blockchum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('blockChum()')) - self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self) - self.connect(self.logchum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('openChumLogs()')) - self.reportchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/report"], self) - self.connect(self.reportchum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('reportChum()')) - self.findalts = QtGui.QAction("Find Alts", self) - self.connect(self.findalts, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('findAlts()')) - self.removegroup = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/removegroup"], self) - self.connect(self.removegroup, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('removeGroup()')) - self.renamegroup = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/renamegroup"], self) - self.connect(self.renamegroup, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('renameGroup()')) - self.notes = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/notes"], self) - self.connect(self.notes, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('editNotes()')) + self.groupMenu = QtWidgets.QMenu(self) + self.canonMenu = QtWidgets.QMenu(self) + self.optionsMenu = QtWidgets.QMenu(self) + self.pester = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self) + self.pester.triggered.connect(self.activateChum) + self.removechum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/removechum"], self) + self.removechum.triggered.connect(self.removeChum) + self.blockchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"], self) + self.blockchum.triggered.connect(self.blockChum) + self.logchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self) + self.logchum.triggered.connect(self.openChumLogs) + self.reportchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/report"], self) + self.reportchum.triggered.connect(self.reportChum) + self.findalts = QtWidgets.QAction("Find Alts", self) + self.findalts.triggered.connect(self.findAlts) + self.removegroup = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/removegroup"], self) + self.removegroup.triggered.connect(self.removeGroup) + self.renamegroup = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/renamegroup"], self) + self.renamegroup.triggered.connect(self.renameGroup) + self.notes = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/notes"], self) + self.notes.triggered.connect(self.editNotes) self.optionsMenu.addAction(self.pester) self.optionsMenu.addAction(self.logchum) self.optionsMenu.addAction(self.notes) self.optionsMenu.addAction(self.blockchum) self.optionsMenu.addAction(self.removechum) - self.moveMenu = QtGui.QMenu(self.mainwindow.theme["main/menus/rclickchumlist/movechum"], self) + self.moveMenu = QtWidgets.QMenu(self.mainwindow.theme["main/menus/rclickchumlist/movechum"], self) self.optionsMenu.addMenu(self.moveMenu) self.optionsMenu.addAction(self.reportchum) self.moveGroupMenu() @@ -324,22 +322,21 @@ class chumArea(RightClickTree): self.setDropIndicatorShown(True) self.setIndentation(4) self.setDragEnabled(True) - self.setDragDropMode(QtGui.QAbstractItemView.InternalMove) + self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) self.setAnimated(True) self.setRootIsDecorated(False) - self.connect(self, QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem *, int)'), - self, QtCore.SLOT('expandGroup()')) + self.itemDoubleClicked[QTreeWidgetItem, int].connect(self.expandGroup) @QtCore.pyqtSlot() def beginNotify(self): - print "BEGIN NOTIFY" + print("BEGIN NOTIFY") self.notify = True def getOptionsMenu(self): if not self.currentItem(): return None - text = unicode(self.currentItem().text(0)) + text = str(self.currentItem().text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] if text == "Chums": @@ -385,13 +382,13 @@ class chumArea(RightClickTree): if thisitem.rfind(" (") != -1: thisitem = thisitem[0:thisitem.rfind(" (")] # Drop item is a group - thisitem = unicode(event.source().currentItem().text(0)) + thisitem = str(event.source().currentItem().text(0)) if thisitem.rfind(" (") != -1: thisitem = thisitem[0:thisitem.rfind(" (")] if thisitem == "Chums" or thisitem in self.groups: droppos = self.itemAt(event.pos()) if not droppos: return - droppos = unicode(droppos.text(0)) + droppos = str(droppos.text(0)) if droppos.rfind(" ") != -1: droppos = droppos[0:droppos.rfind(" ")] if droppos == "Chums" or droppos in self.groups: @@ -404,16 +401,16 @@ class chumArea(RightClickTree): gTemp = [] for i in range(self.topLevelItemCount()): - text = unicode(self.topLevelItem(i).text(0)) + text = str(self.topLevelItem(i).text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] - gTemp.append([unicode(text), self.topLevelItem(i).isExpanded()]) + gTemp.append([str(text), self.topLevelItem(i).isExpanded()]) self.mainwindow.config.saveGroups(gTemp) # Drop item is a chum else: item = self.itemAt(event.pos()) if item: - text = unicode(item.text(0)) + text = str(item.text(0)) # Figure out which group to drop into if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] @@ -421,7 +418,7 @@ class chumArea(RightClickTree): group = text gitem = item else: - ptext = unicode(item.parent().text(0)) + ptext = str(item.parent().text(0)) if ptext.rfind(" ") != -1: ptext = ptext[0:ptext.rfind(" ")] group = ptext @@ -444,7 +441,7 @@ class chumArea(RightClickTree): if chums.index(thisitem) < inPos: inPos -= 1 chums.remove(thisitem) - chums.insert(inPos, unicode(thisitem)) + chums.insert(inPos, str(thisitem)) self.mainwindow.config.setChums(chums) else: @@ -456,14 +453,14 @@ class chumArea(RightClickTree): currentGroup = self.currentItem() if currentGroup: if currentGroup.parent(): - text = unicode(currentGroup.parent().text(0)) + text = str(currentGroup.parent().text(0)) else: - text = unicode(currentGroup.text(0)) + text = str(currentGroup.text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] currentGroup = text self.moveMenu.clear() - actGroup = QtGui.QActionGroup(self) + actGroup = QtWidgets.QActionGroup(self) groups = self.groups[:] for gtext in groups: @@ -471,8 +468,7 @@ class chumArea(RightClickTree): continue movegroup = self.moveMenu.addAction(gtext) actGroup.addAction(movegroup) - self.connect(actGroup, QtCore.SIGNAL('triggered(QAction *)'), - self, QtCore.SLOT('moveToGroup(QAction *)')) + actGroup.triggered[QAction].connect(self.moveToGroup) def addChum(self, chum): if len([c for c in self.chums if c.handle == chum.handle]) != 0: @@ -510,20 +506,20 @@ class chumArea(RightClickTree): def showAllGroups(self, first=False): if first: for i,g in enumerate(self.groups): - child_1 = QtGui.QTreeWidgetItem(["%s" % (g)]) + child_1 = QtWidgets.QTreeWidgetItem(["%s" % (g)]) self.addTopLevelItem(child_1) if self.openGroups[i]: child_1.setExpanded(True) return curgroups = [] for i in range(self.topLevelItemCount()): - text = unicode(self.topLevelItem(i).text(0)) + text = str(self.topLevelItem(i).text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] curgroups.append(text) for i,g in enumerate(self.groups): if g not in curgroups: - child_1 = QtGui.QTreeWidgetItem(["%s" % (g)]) + child_1 = QtWidgets.QTreeWidgetItem(["%s" % (g)]) j = 0 for h in self.groups: if h == g: @@ -541,31 +537,31 @@ class chumArea(RightClickTree): totals = {'Chums': 0} online = {'Chums': 0} for g in self.groups: - totals[unicode(g)] = 0 - online[unicode(g)] = 0 + totals[str(g)] = 0 + online[str(g)] = 0 for c in self.chums: yes = c.mood.name() != "offline" if c.group == "Chums": - totals[unicode(c.group)] = totals[unicode(c.group)]+1 + totals[str(c.group)] = totals[str(c.group)]+1 if yes: - online[unicode(c.group)] = online[unicode(c.group)]+1 + online[str(c.group)] = online[str(c.group)]+1 elif c.group in totals: - totals[unicode(c.group)] = totals[unicode(c.group)]+1 + totals[str(c.group)] = totals[str(c.group)]+1 if yes: - online[unicode(c.group)] = online[unicode(c.group)]+1 + online[str(c.group)] = online[str(c.group)]+1 else: totals["Chums"] = totals["Chums"]+1 if yes: online["Chums"] = online["Chums"]+1 for i in range(self.topLevelItemCount()): - text = unicode(self.topLevelItem(i).text(0)) + text = str(self.topLevelItem(i).text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] if text in online: self.topLevelItem(i).setText(0, "%s (%i/%i)" % (text, online[text], totals[text])) def hideOnlineNumbers(self): for i in range(self.topLevelItemCount()): - text = unicode(self.topLevelItem(i).text(0)) + text = str(self.topLevelItem(i).text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] self.topLevelItem(i).setText(0, "%s" % (text)) @@ -581,7 +577,7 @@ class chumArea(RightClickTree): @QtCore.pyqtSlot() def expandGroup(self): item = self.currentItem() - text = unicode(item.text(0)) + text = str(item.text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] @@ -596,13 +592,13 @@ class chumArea(RightClickTree): self.mainwindow.config.addGroup("Chums") curgroups = [] for i in range(self.topLevelItemCount()): - text = unicode(self.topLevelItem(i).text(0)) + text = str(self.topLevelItem(i).text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] curgroups.append(text) if not self.findItems(chumLabel.handle, QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive): if chumLabel.chum.group not in curgroups: - child_1 = QtGui.QTreeWidgetItem(["%s" % (chumLabel.chum.group)]) + child_1 = QtWidgets.QTreeWidgetItem(["%s" % (chumLabel.chum.group)]) i = 0 for g in self.groups: if g == chumLabel.chum.group: @@ -613,7 +609,7 @@ class chumArea(RightClickTree): if self.openGroups[self.groups.index("%s" % (chumLabel.chum.group))]: child_1.setExpanded(True) for i in range(self.topLevelItemCount()): - text = unicode(self.topLevelItem(i).text(0)) + text = str(self.topLevelItem(i).text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] if text == chumLabel.chum.group: @@ -632,7 +628,7 @@ class chumArea(RightClickTree): bestname = "" if fi > 0: while not bestj: - for j in xrange(self.topLevelItem(i).childCount()): + for j in range(self.topLevelItem(i).childCount()): if chums[fi-c] == str(self.topLevelItem(i).child(j).text(0)): bestj = j bestname = chums[fi-c] @@ -707,7 +703,7 @@ class chumArea(RightClickTree): def initTheme(self, theme): self.resize(*theme["main/chums/size"]) self.move(*theme["main/chums/loc"]) - if theme.has_key("main/chums/scrollbar"): + if "main/chums/scrollbar" in theme: self.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["main/chums/style"], theme["main/chums/scrollbar/style"], theme["main/chums/scrollbar/handle"], theme["main/chums/scrollbar/downarrow"], theme["main/chums/scrollbar/uparrow"], theme["main/chums/scrollbar/uarrowstyle"], theme["main/chums/scrollbar/darrowstyle"] )) else: self.setStyleSheet(theme["main/chums/style"]) @@ -799,8 +795,7 @@ class chumArea(RightClickTree): return currentChum = currentChum.text(0) self.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow) - self.connect(self.pesterlogviewer, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('closeActiveLog()')) + self.pesterlogviewer.rejected.connect(self.closeActiveLog) self.pesterlogviewer.show() self.pesterlogviewer.raise_() self.pesterlogviewer.activateWindow() @@ -813,9 +808,9 @@ class chumArea(RightClickTree): currentChum = self.currentItem() if not currentChum: return - (notes, ok) = QtGui.QInputDialog.getText(self, "Notes", "Enter your notes...") + (notes, ok) = QtWidgets.QInputDialog.getText(self, "Notes", "Enter your notes...") if ok: - notes = unicode(notes) + notes = str(notes) self.mainwindow.chumdb.setNotes(currentChum.handle, notes) currentChum.setToolTip(0, "%s: %s" % (currentChum.handle, notes)) @QtCore.pyqtSlot() @@ -823,13 +818,13 @@ class chumArea(RightClickTree): if not hasattr(self, 'renamegroupdialog'): self.renamegroupdialog = None if not self.renamegroupdialog: - (gname, ok) = QtGui.QInputDialog.getText(self, "Rename Group", "Enter a new name for the group:") + (gname, ok) = QtWidgets.QInputDialog.getText(self, "Rename Group", "Enter a new name for the group:") if ok: - gname = unicode(gname) + gname = str(gname) if re.search("[^A-Za-z0-9_\s]", gname) is not None: - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setInformativeText("THIS IS NOT A VALID GROUP NAME") - msgbox.setStandardButtons(QtGui.QMessageBox.Ok) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) ret = msgbox.exec_() self.addgroupdialog = None return @@ -839,7 +834,7 @@ class chumArea(RightClickTree): index = self.indexOfTopLevelItem(currentGroup) if index != -1: expanded = currentGroup.isExpanded() - text = unicode(currentGroup.text(0)) + text = str(currentGroup.text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] self.mainwindow.config.delGroup(text) @@ -859,7 +854,7 @@ class chumArea(RightClickTree): currentGroup = self.currentItem() if not currentGroup: return - text = unicode(currentGroup.text(0)) + text = str(currentGroup.text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] self.mainwindow.config.delGroup(text) @@ -878,11 +873,11 @@ class chumArea(RightClickTree): self.takeItem(chumLabel) self.addItem(chumLabel) self.takeTopLevelItem(i) - @QtCore.pyqtSlot(QtGui.QAction) + @QtCore.pyqtSlot(QtWidgets.QAction) def moveToGroup(self, item): if not item: return - group = unicode(item.text()) + group = str(item.text()) chumLabel = self.currentItem() if not chumLabel: return @@ -891,19 +886,21 @@ class chumArea(RightClickTree): self.takeItem(chumLabel) self.addItem(chumLabel) - removeChumSignal = QtCore.pyqtSignal(QtCore.QString) - blockChumSignal = QtCore.pyqtSignal(QtCore.QString) + removeChumSignal = QtCore.pyqtSignal('QString') + blockChumSignal = QtCore.pyqtSignal('QString') class trollSlum(chumArea): + unblockChumSignal = QtCore.pyqtSignal() + def __init__(self, trolls, mainwindow, parent=None): #~super(trollSlum, self).__init__(parent) # TODO: Rework inheritance here. - QtGui.QTreeWidgetItem.__init__(self, parent) + QtWidgets.QTreeWidgetItem.__init__(self, parent) self.mainwindow = mainwindow theme = self.mainwindow.theme self.setStyleSheet(theme["main/trollslum/chumroll/style"]) self.chums = trolls - child_1 = QtGui.QTreeWidgetItem([""]) + child_1 = QtWidgets.QTreeWidgetItem([""]) self.addTopLevelItem(child_1) child_1.setExpanded(True) for c in self.chums: @@ -917,10 +914,9 @@ class trollSlum(chumArea): self.setDropIndicatorShown(False) self.setIndentation(0) - self.optionsMenu = QtGui.QMenu(self) - self.unblockchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"], self) - self.connect(self.unblockchum, QtCore.SIGNAL('triggered()'), - self, QtCore.SIGNAL('unblockChumSignal()')) + self.optionsMenu = QtWidgets.QMenu(self) + self.unblockchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"], self) + self.unblockchum.triggered.connect(self.unblockChumSignal) self.optionsMenu.addAction(self.unblockchum) #self.sortItems() @@ -940,30 +936,27 @@ class trollSlum(chumArea): for c in chumlistings: c.changeTheme(theme) - unblockChumSignal = QtCore.pyqtSignal(QtCore.QString) + unblockChumSignal = QtCore.pyqtSignal('QString') -class TrollSlumWindow(QtGui.QFrame): +class TrollSlumWindow(QtWidgets.QFrame): def __init__(self, trolls, mainwindow, parent=None): super(TrollSlumWindow, self).__init__(parent) self.mainwindow = mainwindow theme = self.mainwindow.theme - self.slumlabel = QtGui.QLabel(self) + self.slumlabel = QtWidgets.QLabel(self) self.initTheme(theme) self.trollslum = trollSlum(trolls, self.mainwindow, self) - self.connect(self.trollslum, QtCore.SIGNAL('unblockChumSignal()'), - self, QtCore.SLOT('removeCurrentTroll()')) - layout_1 = QtGui.QHBoxLayout() - self.addButton = QtGui.QPushButton("ADD", self) - self.connect(self.addButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('addTrollWindow()')) - self.removeButton = QtGui.QPushButton("REMOVE", self) - self.connect(self.removeButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('removeCurrentTroll()')) + self.trollslum.unblockChumSignal.connect(self.removeCurrentTroll) + layout_1 = QtWidgets.QHBoxLayout() + self.addButton = QtWidgets.QPushButton("ADD", self) + self.addButton.clicked.connect(self.addTrollWindow) + self.removeButton = QtWidgets.QPushButton("REMOVE", self) + self.removeButton.clicked.connect(self.removeCurrentTroll) layout_1.addWidget(self.addButton) layout_1.addWidget(self.removeButton) - layout_0 = QtGui.QVBoxLayout() + layout_0 = QtWidgets.QVBoxLayout() layout_0.addWidget(self.slumlabel) layout_0.addWidget(self.trollslum) layout_0.addLayout(layout_1) @@ -1002,13 +995,13 @@ class TrollSlumWindow(QtGui.QFrame): self.addtrolldialog = None if self.addtrolldialog: return - self.addtrolldialog = QtGui.QInputDialog(self) + self.addtrolldialog = QtWidgets.QInputDialog(self) (handle, ok) = self.addtrolldialog.getText(self, "Add Troll", "Enter Troll Handle:") if ok: - handle = unicode(handle) + handle = str(handle) if not (PesterProfile.checkLength(handle) and PesterProfile.checkValid(handle)[0]): - errormsg = QtGui.QErrorMessage(self) + errormsg = QtWidgets.QErrorMessage(self) errormsg.showMessage("THIS IS NOT A VALID CHUMTAG!") self.addchumdialog = None return @@ -1016,10 +1009,13 @@ class TrollSlumWindow(QtGui.QFrame): self.blockChumSignal.emit(handle) self.addtrolldialog = None - blockChumSignal = QtCore.pyqtSignal(QtCore.QString) - unblockChumSignal = QtCore.pyqtSignal(QtCore.QString) + blockChumSignal = QtCore.pyqtSignal('QString') + unblockChumSignal = QtCore.pyqtSignal('QString') class PesterWindow(MovingWindow): + reconnectIRC = QtCore.pyqtSignal() + sendMessage = QtCore.pyqtSignal('QString', 'QString') + def __init__(self, options, parent=None, app=None): super(PesterWindow, self).__init__(parent, (QtCore.Qt.CustomizeWindowHint | @@ -1091,7 +1087,7 @@ class PesterWindow(MovingWindow): themeChecker(self.theme) except ThemeException as inst: logging.error("Caught: " + inst.parameter) - themeWarning = QtGui.QMessageBox(self) + themeWarning = QtWidgets.QMessageBox(self) themeWarning.setText("Theme Error: %s" % inst) themeWarning.exec_() self.theme = pesterTheme("pesterchum") @@ -1107,70 +1103,57 @@ class PesterWindow(MovingWindow): self.move(100, 100) - talk = QtGui.QAction(self.theme["main/menus/client/talk"], self) + talk = QtWidgets.QAction(self.theme["main/menus/client/talk"], self) self.talk = talk - self.connect(talk, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('openChat()')) - logv = QtGui.QAction(self.theme["main/menus/client/logviewer"], self) + talk.triggered.connect(self.openChat) + logv = QtWidgets.QAction(self.theme["main/menus/client/logviewer"], self) self.logv = logv - self.connect(logv, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('openLogv()')) - grps = QtGui.QAction(self.theme["main/menus/client/addgroup"], self) + logv.triggered.connect(self.openLogv) + grps = QtWidgets.QAction(self.theme["main/menus/client/addgroup"], self) self.grps = grps - self.connect(grps, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('addGroupWindow()')) - self.rand = QtGui.QAction(self.theme["main/menus/client/randen"], self) - self.connect(self.rand, QtCore.SIGNAL('triggered()'), - self.randhandler, QtCore.SLOT('getEncounter()')) - opts = QtGui.QAction(self.theme["main/menus/client/options"], self) + grps.triggered.connect(self.addGroupWindow) + self.rand = QtWidgets.QAction(self.theme["main/menus/client/randen"], self) + self.rand.triggered.connect(self.randhandler.getEncounter) + opts = QtWidgets.QAction(self.theme["main/menus/client/options"], self) self.opts = opts - self.connect(opts, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('openOpts()')) - exitaction = QtGui.QAction(self.theme["main/menus/client/exit"], self) + opts.triggered.connect(self.openOpts) + exitaction = QtWidgets.QAction(self.theme["main/menus/client/exit"], self) self.exitaction = exitaction - self.connect(exitaction, QtCore.SIGNAL('triggered()'), - self.app, QtCore.SLOT('quit()')) - userlistaction = QtGui.QAction(self.theme["main/menus/client/userlist"], self) + exitaction.triggered.connect(self.app.quit) + userlistaction = QtWidgets.QAction(self.theme["main/menus/client/userlist"], self) self.userlistaction = userlistaction - self.connect(userlistaction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('showAllUsers()')) - memoaction = QtGui.QAction(self.theme["main/menus/client/memos"], self) + userlistaction.triggered.connect(self.showAllUsers) + memoaction = QtWidgets.QAction(self.theme["main/menus/client/memos"], self) self.memoaction = memoaction - self.connect(memoaction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('showMemos()')) - self.importaction = QtGui.QAction(self.theme["main/menus/client/import"], self) - self.connect(self.importaction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('importExternalConfig()')) - self.idleaction = QtGui.QAction(self.theme["main/menus/client/idle"], self) + memoaction.triggered.connect(self.showMemos) + self.importaction = QtWidgets.QAction(self.theme["main/menus/client/import"], self) + self.importaction.triggered.connect(self.importExternalConfig) + self.idleaction = QtWidgets.QAction(self.theme["main/menus/client/idle"], self) self.idleaction.setCheckable(True) - self.connect(self.idleaction, QtCore.SIGNAL('toggled(bool)'), - self, QtCore.SLOT('toggleIdle(bool)')) - self.reconnectAction = QtGui.QAction(self.theme["main/menus/client/reconnect"], self) - self.connect(self.reconnectAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SIGNAL('reconnectIRC()')) + self.idleaction.toggled[bool].connect(self.toggleIdle) + self.reconnectAction = QtWidgets.QAction(self.theme["main/menus/client/reconnect"], self) + self.reconnectAction.triggered.connect(self.reconnectIRC) - self.menu = QtGui.QMenuBar(self) + self.menu = QtWidgets.QMenuBar(self) self.menu.setNativeMenuBar(False) self.menu.setObjectName("mainmenu") self.console = AttrDict(dict( window = None, - action = QtGui.QAction("Console", self), + action = QtWidgets.QAction("Console", self), is_open = False )) self.console.shortcuts = AttrDict(dict( - conkey = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+`"), self, + conkey = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+`"), self, context=QtCore.Qt.ApplicationShortcut), - curwgt = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Alt+w"), self, + curwgt = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+Alt+w"), self, context=QtCore.Qt.ApplicationShortcut) )) - self.connect(self.console.action, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('toggleConsole()')) + self.console.action.triggered.connect(self.toggleConsole) # Make sure the shortcut works anywhere. # karxi: There's something wrong with the inheritance scheme here. #~self.console.shortcuts.conkey.setContext(QtCore.Qt.ApplicationShortcut) - self.connect(self.console.shortcuts.conkey, - QtCore.SIGNAL('activated()'), self, QtCore.SLOT('toggleConsole()')) + self.console.shortcuts.conkey.activated.connect(self.toggleConsole) #~# Use new-style connections #~self.console.shortcut.activated.connect(self.toggleConsole) # Apparently those can crash sometimes...c'est la vie. Can't use 'em. @@ -1196,24 +1179,20 @@ class PesterWindow(MovingWindow): filemenu.addAction(self.reconnectAction) filemenu.addAction(exitaction) - changequirks = QtGui.QAction(self.theme["main/menus/profile/quirks"], self) + changequirks = QtWidgets.QAction(self.theme["main/menus/profile/quirks"], self) self.changequirks = changequirks - self.connect(changequirks, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('openQuirks()')) - loadslum = QtGui.QAction(self.theme["main/menus/profile/block"], self) + changequirks.triggered.connect(self.openQuirks) + loadslum = QtWidgets.QAction(self.theme["main/menus/profile/block"], self) self.loadslum = loadslum - self.connect(loadslum, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('showTrollSlum()')) + loadslum.triggered.connect(self.showTrollSlum) - changecoloraction = QtGui.QAction(self.theme["main/menus/profile/color"], self) + changecoloraction = QtWidgets.QAction(self.theme["main/menus/profile/color"], self) self.changecoloraction = changecoloraction - self.connect(changecoloraction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('changeMyColor()')) + changecoloraction.triggered.connect(self.changeMyColor) - switch = QtGui.QAction(self.theme["main/menus/profile/switch"], self) + switch = QtWidgets.QAction(self.theme["main/menus/profile/switch"], self) self.switch = switch - self.connect(switch, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('switchProfile()')) + switch.triggered.connect(self.switchProfile) profilemenu = self.menu.addMenu(self.theme["main/menus/profile/_name"]) self.profilemenu = profilemenu @@ -1222,24 +1201,18 @@ class PesterWindow(MovingWindow): profilemenu.addAction(changecoloraction) profilemenu.addAction(switch) - self.helpAction = QtGui.QAction(self.theme["main/menus/help/help"], self) - self.connect(self.helpAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('launchHelp()')) - self.botAction = QtGui.QAction(self.theme["main/menus/help/calsprite"], self) - self.connect(self.botAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('loadCalsprite()')) - self.nickServAction = QtGui.QAction(self.theme["main/menus/help/nickserv"], self) - self.connect(self.nickServAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('loadNickServ()')) - self.chanServAction = QtGui.QAction(self.theme["main/menus/help/chanserv"], self) - self.connect(self.chanServAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('loadChanServ()')) - self.aboutAction = QtGui.QAction(self.theme["main/menus/help/about"], self) - self.connect(self.aboutAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('aboutPesterchum()')) - self.reportBugAction = QtGui.QAction("REPORT BUG", self) - self.connect(self.reportBugAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('reportBug()')) + self.helpAction = QtWidgets.QAction(self.theme["main/menus/help/help"], self) + self.helpAction.triggered.connect(self.launchHelp) + self.botAction = QtWidgets.QAction(self.theme["main/menus/help/calsprite"], self) + self.botAction.triggered.connect(self.loadCalsprite) + self.nickServAction = QtWidgets.QAction(self.theme["main/menus/help/nickserv"], self) + self.nickServAction.triggered.connect(self.loadNickServ) + self.chanServAction = QtWidgets.QAction(self.theme["main/menus/help/chanserv"], self) + self.chanServAction.triggered.connect(self.loadChanServ) + self.aboutAction = QtWidgets.QAction(self.theme["main/menus/help/about"], self) + self.aboutAction.triggered.connect(self.aboutPesterchum) + self.reportBugAction = QtWidgets.QAction("REPORT BUG", self) + self.reportBugAction.triggered.connect(self.reportBug) helpmenu = self.menu.addMenu(self.theme["main/menus/help/_name"]) self.helpmenu = helpmenu self.helpmenu.addAction(self.helpAction) @@ -1259,45 +1232,31 @@ class PesterWindow(MovingWindow): chums = [PesterProfile(c, chumdb=self.chumdb) for c in set(self.config.chums())] self.chumList = chumArea(chums, self) - self.connect(self.chumList, - QtCore.SIGNAL('itemActivated(QTreeWidgetItem *, int)'), - self, - QtCore.SLOT('pesterSelectedChum()')) - self.connect(self.chumList, - QtCore.SIGNAL('removeChumSignal(QString)'), - self, - QtCore.SLOT('removeChum(QString)')) - self.connect(self.chumList, - QtCore.SIGNAL('blockChumSignal(QString)'), - self, - QtCore.SLOT('blockChum(QString)')) + self.chumList.itemActivated[QTreeWidgetItem, int].connect(self.pesterSelectedChum) + self.chumList.removeChumSignal['QString'].connect(self.removeChum) + self.chumList.blockChumSignal['QString'].connect(self.blockChum) - self.addChumButton = QtGui.QPushButton(self.theme["main/addchum/text"], self) + self.addChumButton = QtWidgets.QPushButton(self.theme["main/addchum/text"], self) self.addChumButton.setObjectName("addchumbtn") - self.connect(self.addChumButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('addChumWindow()')) - self.pesterButton = QtGui.QPushButton(self.theme["main/pester/text"], self) + self.addChumButton.clicked.connect(self.addChumWindow) + self.pesterButton = QtWidgets.QPushButton(self.theme["main/pester/text"], self) self.pesterButton.setObjectName("newpesterbtn") - self.connect(self.pesterButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('pesterSelectedChum()')) - self.blockButton = QtGui.QPushButton(self.theme["main/block/text"], self) + self.pesterButton.clicked.connect(self.pesterSelectedChum) + self.blockButton = QtWidgets.QPushButton(self.theme["main/block/text"], self) self.blockButton.setObjectName("blockbtn") - self.connect(self.blockButton, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('blockSelectedChum()')) + self.blockButton.clicked.connect(self.blockSelectedChum) - self.moodsLabel = QtGui.QLabel(self.theme["main/moodlabel/text"], self) + self.moodsLabel = QtWidgets.QLabel(self.theme["main/moodlabel/text"], self) self.moodsLabel.setObjectName("moodlabel") - self.mychumhandleLabel = QtGui.QLabel(self.theme["main/mychumhandle/label/text"], self) + self.mychumhandleLabel = QtWidgets.QLabel(self.theme["main/mychumhandle/label/text"], self) self.mychumhandleLabel.setObjectName("myhandlelabel") - self.mychumhandle = QtGui.QPushButton(self.profile().handle, self) + self.mychumhandle = QtWidgets.QPushButton(self.profile().handle, self) self.mychumhandle.setFlat(True) - self.connect(self.mychumhandle, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('switchProfile()')) + self.mychumhandle.clicked.connect(self.switchProfile) - self.mychumcolor = QtGui.QPushButton(self) - self.connect(self.mychumcolor, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('changeMyColor()')) + self.mychumcolor = QtWidgets.QPushButton(self) + self.mychumcolor.clicked.connect(self.changeMyColor) self.initTheme(self.theme) @@ -1319,8 +1278,7 @@ class PesterWindow(MovingWindow): # idletime time = 0 )) - self.connect(self.idler.timer, QtCore.SIGNAL('timeout()'), - self, QtCore.SLOT('checkIdle()')) + self.idler.timer.timeout.connect(self.checkIdle) self.idler.timer.start(1000) if not self.config.defaultprofile(): @@ -1330,12 +1288,10 @@ class PesterWindow(MovingWindow): if not ostools.isOSXLeopard(): QtCore.QTimer.singleShot(1000, self, QtCore.SLOT('mspacheck()')) - self.connect(self, QtCore.SIGNAL('pcUpdate(QString, QString)'), - self, QtCore.SLOT('updateMsg(QString, QString)')) + self.pcUpdate['QString', 'QString'].connect(self.updateMsg) self.pingtimer = QtCore.QTimer() - self.connect(self.pingtimer, QtCore.SIGNAL('timeout()'), - self, QtCore.SLOT('checkPing()')) + self.pingtimer.timeout.connect(self.checkPing) self.lastping = int(time()) self.pingtimer.start(1000*90) @@ -1345,23 +1301,21 @@ class PesterWindow(MovingWindow): if not ostools.isOSXLeopard(): checker = MSPAChecker(self) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def updateMsg(self, ver, url): if not hasattr(self, 'updatemenu'): self.updatemenu = None if not self.updatemenu: self.updatemenu = UpdatePesterchum(ver, url, self) - self.connect(self.updatemenu, QtCore.SIGNAL('accepted()'), - self, QtCore.SLOT('updatePC()')) - self.connect(self.updatemenu, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('noUpdatePC()')) + self.updatemenu.accepted.connect(self.updatePC) + self.updatemenu.rejected.connect(self.noUpdatePC) self.updatemenu.show() self.updatemenu.raise_() self.updatemenu.activateWindow() @QtCore.pyqtSlot() def updatePC(self): - version.updateDownload(unicode(self.updatemenu.url)) + version.updateDownload(str(self.updatemenu.url)) self.updatemenu = None @QtCore.pyqtSlot() def noUpdatePC(self): @@ -1381,7 +1335,7 @@ class PesterWindow(MovingWindow): if self.tabconvo: self.tabconvo.close() else: - for c in self.convos.values(): + for c in list(self.convos.values()): c.close() if self.tabmemo: if not switch: @@ -1390,7 +1344,7 @@ class PesterWindow(MovingWindow): for m in self.tabmemo.convos: self.tabmemo.convos[m].sendtime() else: - for m in self.memos.values(): + for m in list(self.memos.values()): if not switch: m.close() else: @@ -1417,7 +1371,7 @@ class PesterWindow(MovingWindow): return # notify if self.config.notifyOptions() & self.config.NEWMSG: - if not self.convos.has_key(handle): + if handle not in self.convos: t = self.tm.Toast("New Conversation", "From: %s" % handle) t.show() elif not self.config.notifyOptions() & self.config.NEWCONVO: @@ -1435,7 +1389,7 @@ class PesterWindow(MovingWindow): elif msg == "PESTERCHUM:UNBLOCK": t = self.tm.Toast("Unblocked", handle) t.show() - if not self.convos.has_key(handle): + if handle not in self.convos: if msg == "PESTERCHUM:CEASE": # ignore cease after we hang up return matchingChums = [c for c in self.chumList.chums if c.handle == handle] @@ -1457,13 +1411,13 @@ class PesterWindow(MovingWindow): else: self.alarm.play() def newMemoMsg(self, chan, handle, msg): - if not self.memos.has_key(chan): + if chan not in self.memos: # silently ignore in case we forgot to /part # TODO: This is really bad practice. Fix it later. return memo = self.memos[chan] - msg = unicode(msg) - if not memo.times.has_key(handle): + msg = str(msg) + if handle not in memo.times: # new chum! time current newtime = timedelta(0) time = TimeTracker(newtime) @@ -1503,19 +1457,19 @@ class PesterWindow(MovingWindow): def changeColor(self, handle, color): # pesterconvo and chumlist self.chumList.updateColor(handle, color) - if self.convos.has_key(handle): + if handle in self.convos: self.convos[handle].updateColor(color) self.chumdb.setColor(handle, color) def updateMood(self, handle, mood): # updates OTHER chums' moods oldmood = self.chumList.updateMood(handle, mood) - if self.convos.has_key(handle): + if handle in self.convos: self.convos[handle].updateMood(mood, old=oldmood) if hasattr(self, 'trollslum') and self.trollslum: self.trollslum.updateMood(handle, mood) def newConversation(self, chum, initiated=True): - if type(chum) in [str, unicode]: + if type(chum) in [str, str]: matchingChums = [c for c in self.chumList.chums if c.handle == chum] if len(matchingChums) > 0: mood = matchingChums[0].mood @@ -1525,7 +1479,7 @@ class PesterWindow(MovingWindow): if len(matchingChums) == 0: self.moodRequest.emit(chum) - if self.convos.has_key(chum.handle): + if chum.handle in self.convos: self.convos[chum.handle].showChat() return if self.config.tabs(): @@ -1535,28 +1489,24 @@ class PesterWindow(MovingWindow): self.tabconvo.show() else: convoWindow = PesterConvo(chum, initiated, self) - self.connect(convoWindow, QtCore.SIGNAL('messageSent(QString, QString)'), - self, QtCore.SIGNAL('sendMessage(QString, QString)')) - self.connect(convoWindow, QtCore.SIGNAL('windowClosed(QString)'), - self, QtCore.SLOT('closeConvo(QString)')) + convoWindow.messageSent['QString', 'QString'].connect(self.sendMessage['QString', 'QString']) + convoWindow.windowClosed['QString'].connect(self.closeConvo) self.convos[chum.handle] = convoWindow - if unicode(chum.handle).upper() in BOTNAMES: + if str(chum.handle).upper() in BOTNAMES: convoWindow.toggleQuirks(True) convoWindow.quirksOff.setChecked(True) - if unicode(chum.handle).upper() in CUSTOMBOTS: - self.newConvoStarted.emit(QtCore.QString(chum.handle), initiated) + if str(chum.handle).upper() in CUSTOMBOTS: + self.newConvoStarted.emit(QString(chum.handle), initiated) else: - self.newConvoStarted.emit(QtCore.QString(chum.handle), initiated) + self.newConvoStarted.emit(QString(chum.handle), initiated) convoWindow.show() def createTabWindow(self): self.tabconvo = PesterTabWindow(self) - self.connect(self.tabconvo, QtCore.SIGNAL('windowClosed()'), - self, QtCore.SLOT('tabsClosed()')) + self.tabconvo.windowClosed.connect(self.tabsClosed) def createMemoTabWindow(self): self.tabmemo = MemoTabWindow(self) - self.connect(self.tabmemo, QtCore.SIGNAL('windowClosed()'), - self, QtCore.SLOT('memoTabsClosed()')) + self.tabmemo.windowClosed.connect(self.memoTabsClosed) @QtCore.pyqtSlot() def toggleConsole(self): @@ -1569,14 +1519,11 @@ class PesterWindow(MovingWindow): logging.warning("Making a console....") self.console.window = win = console.ConsoleWindow(parent=self) logging.warning("Console made.") - self.connect(win, QtCore.SIGNAL('windowClosed()'), - self, QtCore.SLOT('consoleWindowClosed()')) - self.connect(self.console.shortcuts.curwgt, - QtCore.SIGNAL('activated()'), - win, QtCore.SLOT('designateCurrentWidget()')) + win.windowClosed.connect(self.consoleWindowClosed) + self.console.shortcuts.curwgt.activated.connect(win.designateCurrentWidget) if self.console.is_open: - for wgt in win.findChildren(QtGui.QWidget): + for wgt in win.findChildren(QtWidgets.QWidget): try: focused = wgt.hasFocus() except AttributeError: @@ -1630,7 +1577,7 @@ class PesterWindow(MovingWindow): def newMemo(self, channel, timestr, secret=False, invite=False): if channel == "#pesterchum": return - if self.memos.has_key(channel): + if channel in self.memos: self.memos[channel].showChat() return # do slider dialog then set @@ -1642,19 +1589,12 @@ class PesterWindow(MovingWindow): else: memoWindow = PesterMemo(channel, timestr, self, None) # connect signals - self.connect(self, QtCore.SIGNAL('inviteOnlyChan(QString)'), - memoWindow, QtCore.SLOT('closeInviteOnly(QString)')) - self.connect(memoWindow, QtCore.SIGNAL('messageSent(QString, QString)'), - self, QtCore.SIGNAL('sendMessage(QString, QString)')) - self.connect(memoWindow, QtCore.SIGNAL('windowClosed(QString)'), - self, QtCore.SLOT('closeMemo(QString)')) - self.connect(self, QtCore.SIGNAL('namesUpdated(QString)'), - memoWindow, QtCore.SLOT('namesUpdated(QString)')) - self.connect(self, QtCore.SIGNAL('modesUpdated(QString, QString)'), - memoWindow, QtCore.SLOT('modesUpdated(QString, QString)')) - self.connect(self, - QtCore.SIGNAL('userPresentSignal(QString, QString, QString)'), - memoWindow, QtCore.SLOT('userPresentChange(QString, QString, QString)')) + self.inviteOnlyChan['QString'].connect(memoWindow.closeInviteOnly) + memoWindow.messageSent['QString', 'QString'].connect(self.sendMessage['QString', 'QString']) + memoWindow.windowClosed['QString'].connect(self.closeMemo) + self.namesUpdated['QString'].connect(memoWindow.namesUpdated) + self.modesUpdated['QString', 'QString'].connect(memoWindow.modesUpdated) + self.userPresentSignal['QString', 'QString', 'QString'].connect(memoWindow.userPresentChange) # chat client send memo open self.memos[channel] = memoWindow self.joinChannel.emit(channel) # race condition? @@ -1751,19 +1691,19 @@ class PesterWindow(MovingWindow): if hasattr(self, 'moods'): self.moods.removeButtons() mood_list = theme["main/moods"] - mood_list = [dict([(str(k),v) for (k,v) in d.iteritems()]) + mood_list = [dict([(str(k),v) for (k,v) in d.items()]) for d in mood_list] self.moods = PesterMoodHandler(self, *[PesterMoodButton(self, **d) for d in mood_list]) self.moods.showButtons() # chum addChumStyle = "QPushButton { %s }" % (theme["main/addchum/style"]) - if theme.has_key("main/addchum/pressed"): + if "main/addchum/pressed" in theme: addChumStyle += "QPushButton:pressed { %s }" % (theme["main/addchum/pressed"]) pesterButtonStyle = "QPushButton { %s }" % (theme["main/pester/style"]) - if theme.has_key("main/pester/pressed"): + if "main/pester/pressed" in theme: pesterButtonStyle += "QPushButton:pressed { %s }" % (theme["main/pester/pressed"]) blockButtonStyle = "QPushButton { %s }" % (theme["main/block/style"]) - if theme.has_key("main/block/pressed"): + if "main/block/pressed" in theme: pesterButtonStyle += "QPushButton:pressed { %s }" % (theme["main/block/pressed"]) self.addChumButton.setText(theme["main/addchum/text"]) self.addChumButton.resize(*theme["main/addchum/size"]) @@ -1788,12 +1728,12 @@ class PesterWindow(MovingWindow): self.mychumcolor.resize(*theme["main/mychumhandle/colorswatch/size"]) self.mychumcolor.move(*theme["main/mychumhandle/colorswatch/loc"]) self.mychumcolor.setStyleSheet("background: %s" % (self.profile().colorhtml())) - if self.theme.has_key("main/mychumhandle/currentMood"): + if "main/mychumhandle/currentMood" in self.theme: moodicon = self.profile().mood.icon(theme) if hasattr(self, 'currentMoodIcon') and self.currentMoodIcon: self.currentMoodIcon.hide() self.currentMoodIcon = None - self.currentMoodIcon = QtGui.QLabel(self) + self.currentMoodIcon = QtWidgets.QLabel(self) self.currentMoodIcon.setPixmap(moodicon.pixmap(moodicon.realsize())) self.currentMoodIcon.move(*theme["main/mychumhandle/currentMood"]) self.currentMoodIcon.show() @@ -1825,9 +1765,9 @@ class PesterWindow(MovingWindow): if (pygame and pygame.mixer): # We have pygame, so we may as well use it. soundclass = pygame.mixer.Sound - elif QtGui.QSound.isAvailable(): + elif QtMultimedia.QSound.isAvailable(): # We don't have pygame; try to use QSound. - soundclass = QtGui.QSound + soundclass = QtMultimedia.QSound else: # We don't have any options...just use fillers. soundclass = NoneSound @@ -1866,7 +1806,7 @@ class PesterWindow(MovingWindow): if pygame and pygame.mixer and \ isinstance(sound, pygame.mixer.sound): sound.set_volume(vol) - elif not isinstance(sound, QtGui.QSound): + elif not isinstance(sound, QtMultimedia.QSound): # We can't set a volume on those.... sound.setVolume(vol) except Exception as err: @@ -1889,7 +1829,7 @@ class PesterWindow(MovingWindow): try: themeChecker(theme) except ThemeException as inst: - themeWarning = QtGui.QMessageBox(self) + themeWarning = QtWidgets.QMessageBox(self) themeWarning.setText("Theme Error: %s" % inst) themeWarning.exec_() theme = pesterTheme("pesterchum") @@ -1906,9 +1846,9 @@ class PesterWindow(MovingWindow): self.tabconvo.changeTheme(theme) if self.tabmemo: self.tabmemo.changeTheme(theme) - for c in self.convos.values(): + for c in list(self.convos.values()): c.changeTheme(theme) - for m in self.memos.values(): + for m in list(self.memos.values()): m.changeTheme(theme) if hasattr(self, 'trollslum') and self.trollslum: self.trollslum.changeTheme(theme) @@ -1955,7 +1895,7 @@ class PesterWindow(MovingWindow): @QtCore.pyqtSlot() def connected(self): if self.loadingscreen: - self.loadingscreen.done(QtGui.QDialog.Accepted) + self.loadingscreen.done(QtWidgets.QDialog.Accepted) self.loadingscreen = None self.doAutoIdentify() @@ -1971,13 +1911,13 @@ class PesterWindow(MovingWindow): def pesterSelectedChum(self): curChum = self.chumList.currentItem() if curChum: - text = unicode(curChum.text(0)) + text = str(curChum.text(0)) if text.rfind(" (") != -1: text = text[0:text.rfind(" (")] if text not in self.chumList.groups and \ text != "Chums": self.newConversationWindow(curChum) - @QtCore.pyqtSlot(QtGui.QListWidgetItem) + @QtCore.pyqtSlot(QtWidgets.QListWidgetItem) def newConversationWindow(self, chumlisting): # check chumdb chum = chumlisting.chum @@ -1985,9 +1925,9 @@ class PesterWindow(MovingWindow): if color: chum.color = color self.newConversation(chum) - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def closeConvo(self, handle): - h = unicode(handle) + h = str(handle) try: chum = self.convos[h].chum except KeyError: @@ -2001,9 +1941,9 @@ class PesterWindow(MovingWindow): self.convoClosed.emit(handle) self.chatlog.finish(h) del self.convos[h] - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def closeMemo(self, channel): - c = unicode(channel) + c = str(channel) self.chatlog.finish(c) self.leftChannel.emit(channel) try: @@ -2019,54 +1959,54 @@ class PesterWindow(MovingWindow): del self.tabmemo self.tabmemo = None - @QtCore.pyqtSlot(QtCore.QString, Mood) + @QtCore.pyqtSlot(QString, Mood) def updateMoodSlot(self, handle, mood): - h = unicode(handle) + h = str(handle) self.updateMood(h, mood) - @QtCore.pyqtSlot(QtCore.QString, QtGui.QColor) + @QtCore.pyqtSlot(QString, QtGui.QColor) def updateColorSlot(self, handle, color): - h = unicode(handle) + h = str(handle) self.changeColor(h, color) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def deliverMessage(self, handle, msg): - h = unicode(handle) - m = unicode(msg) + h = str(handle) + m = str(msg) self.newMessage(h, m) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString, QString) def deliverMemo(self, chan, handle, msg): - (c, h, m) = (unicode(chan), unicode(handle), unicode(msg)) + (c, h, m) = (str(chan), str(handle), str(msg)) self.newMemoMsg(c,h,m) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def deliverNotice(self, handle, msg): - h = unicode(handle) - m = unicode(msg) + h = str(handle) + m = str(msg) if h.upper() == "NICKSERV" and m.startswith("Your nickname is now being changed to"): changedto = m[39:-1] - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setText("This chumhandle has been registered; you may not use it.") msgbox.setInformativeText("Your handle is now being changed to %s." % (changedto)) - msgbox.setStandardButtons(QtGui.QMessageBox.Ok) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) ret = msgbox.exec_() elif h == self.randhandler.randNick: self.randhandler.incoming(msg) - elif self.convos.has_key(h): + elif h in self.convos: self.newMessage(h, m) elif h.upper() == "NICKSERV" and "PESTERCHUM:" not in m: m = nickservmsgs.translate(m) if m: t = self.tm.Toast("NickServ:", m) t.show() - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def deliverInvite(self, handle, channel): - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setText("You're invited!") msgbox.setInformativeText("%s has invited you to the memo: %s\nWould you like to join them?" % (handle, channel)) - msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) # Find the Cancel button and make it default for b in msgbox.buttons(): - if msgbox.buttonRole(b) == QtGui.QMessageBox.RejectRole: + if msgbox.buttonRole(b) == QtWidgets.QMessageBox.RejectRole: # We found the 'OK' button, set it as the default b.setDefault(True) b.setAutoDefault(True) @@ -2075,48 +2015,48 @@ class PesterWindow(MovingWindow): b.setFocus() break ret = msgbox.exec_() - if ret == QtGui.QMessageBox.Ok: - self.newMemo(unicode(channel), "+0:00") - @QtCore.pyqtSlot(QtCore.QString) + if ret == QtWidgets.QMessageBox.Ok: + self.newMemo(str(channel), "+0:00") + @QtCore.pyqtSlot(QString) def chanInviteOnly(self, channel): self.inviteOnlyChan.emit(channel) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def cannotSendToChan(self, channel, msg): self.deliverMemo(channel, "ChanServ", msg) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def modesUpdated(self, channel, modes): self.modesUpdated.emit(channel, modes) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString, QString) def timeCommand(self, chan, handle, command): - (c, h, cmd) = (unicode(chan), unicode(handle), unicode(command)) + (c, h, cmd) = (str(chan), str(handle), str(command)) if self.memos[c]: self.memos[c].timeUpdate(h, cmd) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString, QString) def quirkDisable(self, channel, msg, op): - (c, msg, op) = (unicode(channel), unicode(msg), unicode(op)) - if not self.memos.has_key(c): + (c, msg, op) = (str(channel), str(msg), str(op)) + if c not in self.memos: return memo = self.memos[c] memo.quirkDisable(op, msg) - @QtCore.pyqtSlot(QtCore.QString, PesterList) + @QtCore.pyqtSlot(QString, PesterList) def updateNames(self, channel, names): - c = unicode(channel) + c = str(channel) # update name DB self.namesdb[c] = names # warn interested party of names self.namesUpdated.emit(c) - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString, QString) def userPresentUpdate(self, handle, channel, update): - c = unicode(channel) - n = unicode(handle) + c = str(channel) + n = str(handle) if update == "nick": l = n.split(":") oldnick = l[0] newnick = l[1] if update in ("quit", "netsplit"): - for c in self.namesdb.keys(): + for c in list(self.namesdb.keys()): try: i = self.namesdb[c].index(n) self.namesdb[c].pop(i) @@ -2133,7 +2073,7 @@ class PesterWindow(MovingWindow): except KeyError: self.namesdb[c] = [] elif update == "nick": - for c in self.namesdb.keys(): + for c in list(self.namesdb.keys()): try: i = self.namesdb[c].index(oldnick) self.namesdb[c].pop(i) @@ -2160,23 +2100,23 @@ class PesterWindow(MovingWindow): available_groups = [g[0] for g in self.config.getGroups()] self.addchumdialog = AddChumDialog(available_groups, self) ok = self.addchumdialog.exec_() - handle = unicode(self.addchumdialog.chumBox.text()).strip() - newgroup = unicode(self.addchumdialog.newgroup.text()).strip() + handle = str(self.addchumdialog.chumBox.text()).strip() + newgroup = str(self.addchumdialog.newgroup.text()).strip() selectedGroup = self.addchumdialog.groupBox.currentText() group = newgroup if newgroup else selectedGroup if ok: - handle = unicode(handle) + handle = str(handle) if handle in [h.handle for h in self.chumList.chums]: self.addchumdialog = None return if not (PesterProfile.checkLength(handle) and PesterProfile.checkValid(handle)[0]): - errormsg = QtGui.QErrorMessage(self) + errormsg = QtWidgets.QErrorMessage(self) errormsg.showMessage("THIS IS NOT A VALID CHUMTAG!") self.addchumdialog = None return if re.search("[^A-Za-z0-9_\s]", group) is not None: - errormsg = QtGui.QErrorMessage(self) + errormsg = QtWidgets.QErrorMessage(self) errormsg.showMessage("THIS IS NOT A VALID GROUP NAME") self.addchumdialog = None return @@ -2187,20 +2127,20 @@ class PesterWindow(MovingWindow): self.chumdb.setGroup(handle, group) self.addChum(chum) self.addchumdialog = None - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def removeChum(self, chumlisting): self.config.removeChum(chumlisting) def reportChum(self, handle): - (reason, ok) = QtGui.QInputDialog.getText(self, "Report User", "Enter the reason you are reporting this user (optional):") + (reason, ok) = QtWidgets.QInputDialog.getText(self, "Report User", "Enter the reason you are reporting this user (optional):") if ok: self.sendMessage.emit("REPORT %s %s" % (handle, reason) , "calSprite") - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def blockChum(self, handle): - h = unicode(handle) + h = str(handle) self.config.addBlocklist(h) self.config.removeChum(h) - if self.convos.has_key(h): + if h in self.convos: convo = self.convos[h] msg = self.profile().pestermsg(convo.chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/blocked"]) convo.textArea.append(convertTags(msg)) @@ -2213,11 +2153,11 @@ class PesterWindow(MovingWindow): self.moodRequest.emit(newtroll) self.blockedChum.emit(handle) - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def unblockChum(self, handle): - h = unicode(handle) + h = str(handle) self.config.delBlocklist(h) - if self.convos.has_key(h): + if h in self.convos: convo = self.convos[h] msg = self.profile().pestermsg(convo.chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/unblocked"]) convo.textArea.append(convertTags(msg)) @@ -2286,7 +2226,7 @@ class PesterWindow(MovingWindow): # Tell everyone we're in a chat with that we just went idle. sysColor = QtGui.QColor(self.theme["convo/systemMsgColor"]) verb = self.theme["convo/text/idle"] - for (h, convo) in self.convos.iteritems(): + for (h, convo) in self.convos.items(): # karxi: There's an irritating issue here involving a lack of # consideration for case-sensitivity. # This fix is a little sloppy, and I need to look into what it @@ -2310,12 +2250,12 @@ class PesterWindow(MovingWindow): @QtCore.pyqtSlot() def importExternalConfig(self): - f = QtGui.QFileDialog.getOpenFileName(self) + f = QtWidgets.QFileDialog.getOpenFileName(self)[0] if f == "": return fp = open(f, 'r') regexp_state = None - for l in fp.xreadlines(): + for l in fp: # import chumlist l = l.rstrip() chum_mo = re.match("handle: ([A-Za-z0-9]+)", l) @@ -2329,7 +2269,7 @@ class PesterWindow(MovingWindow): replace = replace_mo.group(1) try: re.compile(regexp_state) - except re.error, e: + except re.error as e: continue newquirk = pesterQuirk({"type": "regexp", "from": regexp_state, @@ -2358,32 +2298,30 @@ class PesterWindow(MovingWindow): if self.memochooser: return self.memochooser = PesterMemoList(self, channel) - self.connect(self.memochooser, QtCore.SIGNAL('accepted()'), - self, QtCore.SLOT('joinSelectedMemo()')) - self.connect(self.memochooser, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('memoChooserClose()')) + self.memochooser.accepted.connect(self.joinSelectedMemo) + self.memochooser.rejected.connect(self.memoChooserClose) self.requestChannelList.emit() self.memochooser.show() @QtCore.pyqtSlot() def joinSelectedMemo(self): - time = unicode(self.memochooser.timeinput.text()) + time = str(self.memochooser.timeinput.text()) secret = self.memochooser.secretChannel.isChecked() invite = self.memochooser.inviteChannel.isChecked() # Join the ones on the list first for SelectedMemo in self.memochooser.SelectedMemos(): - channel = "#"+unicode(SelectedMemo.target) + channel = "#"+str(SelectedMemo.target) self.newMemo(channel, time) if self.memochooser.newmemoname(): newmemo = self.memochooser.newmemoname() - channel = unicode(newmemo).replace(" ", "_") + channel = str(newmemo).replace(" ", "_") channel = re.sub(r"[^A-Za-z0-9#_\,]", "", channel) # Allow us to join more than one with this. chans = channel.split(',') # Filter out empty entries. - chans = filter(None, chans) + chans = [_f for _f in chans if _f] for c in chans: c = '#' + c # We should really change this code to only make the memo once @@ -2405,25 +2343,21 @@ class PesterWindow(MovingWindow): self.allusers = None if not self.allusers: self.allusers = PesterUserlist(self.config, self.theme, self) - self.connect(self.allusers, QtCore.SIGNAL('accepted()'), - self, QtCore.SLOT('userListClose()')) - self.connect(self.allusers, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('userListClose()')) - self.connect(self.allusers, QtCore.SIGNAL('addChum(QString)'), - self, QtCore.SLOT('userListAdd(QString)')) - self.connect(self.allusers, QtCore.SIGNAL('pesterChum(QString)'), - self, QtCore.SLOT('userListPester(QString)')) + self.allusers.accepted.connect(self.userListClose) + self.allusers.rejected.connect(self.userListClose) + self.allusers.addChum['QString'].connect(self.userListAdd) + self.allusers.pesterChum['QString'].connect(self.userListPester) self.requestNames.emit("#pesterchum") self.allusers.show() - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def userListAdd(self, handle): - h = unicode(handle) + h = str(handle) chum = PesterProfile(h, chumdb=self.chumdb) self.addChum(chum) - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def userListPester(self, handle): - h = unicode(handle) + h = str(handle) self.newConversation(h) @QtCore.pyqtSlot() def userListClose(self): @@ -2435,17 +2369,15 @@ class PesterWindow(MovingWindow): self.quirkmenu = None if not self.quirkmenu: self.quirkmenu = PesterChooseQuirks(self.config, self.theme, self) - self.connect(self.quirkmenu, QtCore.SIGNAL('accepted()'), - self, QtCore.SLOT('updateQuirks()')) - self.connect(self.quirkmenu, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('closeQuirks()')) + self.quirkmenu.accepted.connect(self.updateQuirks) + self.quirkmenu.rejected.connect(self.closeQuirks) self.quirkmenu.show() self.quirkmenu.raise_() self.quirkmenu.activateWindow() @QtCore.pyqtSlot() def updateQuirks(self): for i in range(self.quirkmenu.quirkList.topLevelItemCount()): - curgroup = unicode(self.quirkmenu.quirkList.topLevelItem(i).text(0)) + curgroup = str(self.quirkmenu.quirkList.topLevelItem(i).text(0)) for j in range(self.quirkmenu.quirkList.topLevelItem(i).childCount()): item = self.quirkmenu.quirkList.topLevelItem(i).child(j) item.quirk.quirk["on"] = item.quirk.on = (item.checkState(0) == QtCore.Qt.Checked) @@ -2465,10 +2397,10 @@ class PesterWindow(MovingWindow): if not hasattr(self, "openchatdialog"): self.openchatdialog = None if not self.openchatdialog: - (chum, ok) = QtGui.QInputDialog.getText(self, "Pester Chum", "Enter a handle to pester:") + (chum, ok) = QtWidgets.QInputDialog.getText(self, "Pester Chum", "Enter a handle to pester:") try: if ok: - self.newConversation(unicode(chum)) + self.newConversation(str(chum)) except: pass finally: @@ -2479,10 +2411,8 @@ class PesterWindow(MovingWindow): self.logusermenu = None if not self.logusermenu: self.logusermenu = PesterLogUserSelect(self.config, self.theme, self) - self.connect(self.logusermenu, QtCore.SIGNAL('accepted()'), - self, QtCore.SLOT('closeLogUsers()')) - self.connect(self.logusermenu, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('closeLogUsers()')) + self.logusermenu.accepted.connect(self.closeLogUsers) + self.logusermenu.rejected.connect(self.closeLogUsers) self.logusermenu.show() self.logusermenu.raise_() self.logusermenu.activateWindow() @@ -2496,13 +2426,13 @@ class PesterWindow(MovingWindow): if not hasattr(self, 'addgroupdialog'): self.addgroupdialog = None if not self.addgroupdialog: - (gname, ok) = QtGui.QInputDialog.getText(self, "Add Group", "Enter a name for the new group:") + (gname, ok) = QtWidgets.QInputDialog.getText(self, "Add Group", "Enter a name for the new group:") if ok: - gname = unicode(gname) + gname = str(gname) if re.search("[^A-Za-z0-9_\s]", gname) is not None: - msgbox = QtGui.QMessageBox() + msgbox = QtWidgets.QMessageBox() msgbox.setInformativeText("THIS IS NOT A VALID GROUP NAME") - msgbox.setStandardButtons(QtGui.QMessageBox.Ok) + msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) ret = msgbox.exec_() self.addgroupdialog = None return @@ -2515,10 +2445,8 @@ class PesterWindow(MovingWindow): self.optionmenu = None if not self.optionmenu: self.optionmenu = PesterOptions(self.config, self.theme, self) - self.connect(self.optionmenu, QtCore.SIGNAL('accepted()'), - self, QtCore.SLOT('updateOptions()')) - self.connect(self.optionmenu, QtCore.SIGNAL('rejected()'), - self, QtCore.SLOT('closeOptions()')) + self.optionmenu.accepted.connect(self.updateOptions) + self.optionmenu.rejected.connect(self.closeOptions) self.optionmenu.show() self.optionmenu.raise_() self.optionmenu.activateWindow() @@ -2550,7 +2478,7 @@ class PesterWindow(MovingWindow): # combine self.createTabWindow() newconvos = {} - for (h,c) in self.convos.iteritems(): + for (h,c) in self.convos.items(): c.setParent(self.tabconvo) self.tabconvo.addChat(c) self.tabconvo.show() @@ -2580,7 +2508,7 @@ class PesterWindow(MovingWindow): # combine newmemos = {} self.createMemoTabWindow() - for (h,m) in self.memos.iteritems(): + for (h,m) in self.memos.items(): m.setParent(self.tabmemo) self.tabmemo.addChat(m) self.tabmemo.show() @@ -2629,7 +2557,7 @@ class PesterWindow(MovingWindow): # timestamps timestampsetting = self.optionmenu.timestampcheck.isChecked() self.config.set("showTimeStamps", timestampsetting) - timeformatsetting = unicode(self.optionmenu.timestampBox.currentText()) + timeformatsetting = str(self.optionmenu.timestampBox.currentText()) if timeformatsetting == "12 hour": self.config.set("time12Format", True) else: @@ -2739,7 +2667,7 @@ class PesterWindow(MovingWindow): self.config.set('blink', blinksetting) # toast notifications self.tm.setEnabled(self.optionmenu.notifycheck.isChecked()) - self.tm.setCurrentType(unicode(self.optionmenu.notifyOptions.currentText())) + self.tm.setCurrentType(str(self.optionmenu.notifyOptions.currentText())) notifysetting = 0 if self.optionmenu.notifySigninCheck.isChecked(): notifysetting |= self.config.SIGNIN @@ -2786,24 +2714,18 @@ class PesterWindow(MovingWindow): def setButtonAction(self, button, setting, old): if old == 0: # minimize to taskbar - self.disconnect(button, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('showMinimized()')); + button.clicked.disconnect(self.showMinimized) elif old == 1: # minimize to tray - self.disconnect(button, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('closeToTray()')); + button.clicked.disconnect(self.closeToTray) elif old == 2: # quit - self.disconnect(button, QtCore.SIGNAL('clicked()'), - self.app, QtCore.SLOT('quit()')); + button.clicked.disconnect(self.app.quit) if setting == 0: # minimize to taskbar - self.connect(button, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('showMinimized()')); + button.clicked.connect(self.showMinimized) elif setting == 1: # minimize to tray - self.connect(button, QtCore.SIGNAL('clicked()'), - self, QtCore.SLOT('closeToTray()')); + button.clicked.connect(self.closeToTray) elif setting == 2: # quit - self.connect(button, QtCore.SIGNAL('clicked()'), - self.app, QtCore.SLOT('quit()')); + button.clicked.connect(self.app.quit) @QtCore.pyqtSlot() def themeSelectOverride(self): @@ -2812,14 +2734,14 @@ class PesterWindow(MovingWindow): @QtCore.pyqtSlot() def themeSelected(self, override=False): if not override: - themename = unicode(self.optionmenu.themeBox.currentText()) + themename = str(self.optionmenu.themeBox.currentText()) else: themename = override if override or themename != self.theme.name: try: self.changeTheme(pesterTheme(themename)) except ValueError as e: - themeWarning = QtGui.QMessageBox(self) + themeWarning = QtWidgets.QMessageBox(self) themeWarning.setText("Theme Error: %s" % (e)) themeWarning.exec_() self.choosetheme = None @@ -2834,14 +2756,14 @@ class PesterWindow(MovingWindow): def profileSelected(self): if self.chooseprofile.profileBox and \ self.chooseprofile.profileBox.currentIndex() > 0: - handle = unicode(self.chooseprofile.profileBox.currentText()) + handle = str(self.chooseprofile.profileBox.currentText()) if handle == self.profile().handle: self.chooseprofile = None return self.userprofile = userProfile(handle) self.changeTheme(self.userprofile.getTheme()) else: - handle = unicode(self.chooseprofile.chumHandle.text()) + handle = str(self.chooseprofile.chumHandle.text()) if handle == self.profile().handle: self.chooseprofile = None return @@ -2868,11 +2790,8 @@ class PesterWindow(MovingWindow): return trolls = [PesterProfile(h) for h in self.config.getBlocklist()] self.trollslum = TrollSlumWindow(trolls, self) - self.connect(self.trollslum, QtCore.SIGNAL('blockChumSignal(QString)'), - self, QtCore.SLOT('blockChum(QString)')) - self.connect(self.trollslum, - QtCore.SIGNAL('unblockChumSignal(QString)'), - self, QtCore.SLOT('unblockChum(QString)')) + self.trollslum.blockChumSignal['QString'].connect(self.blockChum) + self.trollslum.unblockChumSignal['QString'].connect(self.unblockChum) self.moodsRequest.emit(PesterList(trolls)) self.trollslum.show() @QtCore.pyqtSlot() @@ -2884,7 +2803,7 @@ class PesterWindow(MovingWindow): self.colorDialog = None if self.colorDialog: return - self.colorDialog = QtGui.QColorDialog(self) + self.colorDialog = QtWidgets.QColorDialog(self) color = self.colorDialog.getColor(initial=self.profile().color) if not color.isValid(): color = self.profile().color @@ -2898,13 +2817,13 @@ class PesterWindow(MovingWindow): @QtCore.pyqtSlot() def switchProfile(self): if self.convos: - closeWarning = QtGui.QMessageBox() + closeWarning = QtWidgets.QMessageBox() closeWarning.setText("WARNING: CHANGING PROFILES WILL CLOSE ALL CONVERSATION WINDOWS!") closeWarning.setInformativeText("i warned you about windows bro!!!! i told you dog!") - closeWarning.setStandardButtons(QtGui.QMessageBox.Cancel | QtGui.QMessageBox.Ok) - closeWarning.setDefaultButton(QtGui.QMessageBox.Ok) + closeWarning.setStandardButtons(QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.Ok) + closeWarning.setDefaultButton(QtWidgets.QMessageBox.Ok) ret = closeWarning.exec_() - if ret == QtGui.QMessageBox.Cancel: + if ret == QtWidgets.QMessageBox.Cancel: return self.changeProfile() @QtCore.pyqtSlot() @@ -2931,7 +2850,7 @@ class PesterWindow(MovingWindow): QtGui.QDesktopServices.openUrl(QtCore.QUrl("https://github.com/Dpeta/pesterchum-alt-servers/issues", QtCore.QUrl.TolerantMode)) return - @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + @QtCore.pyqtSlot(QString, QString) def nickCollision(self, handle, tmphandle): self.mychumhandle.setText(tmphandle) self.userprofile = userProfile(PesterProfile("pesterClient%d" % (random.randint(100,999)), QtGui.QColor("black"), Mood(0))) @@ -2940,9 +2859,9 @@ class PesterWindow(MovingWindow): if not hasattr(self, 'chooseprofile'): self.chooseprofile = None if not self.chooseprofile: - h = unicode(handle) + h = str(handle) self.changeProfile(collision=h) - @QtCore.pyqtSlot(QtCore.QString) + @QtCore.pyqtSlot(QString) def myHandleChanged(self, handle): if self.profile().handle == handle: self.doAutoIdentify() @@ -2954,57 +2873,57 @@ class PesterWindow(MovingWindow): def pickTheme(self): self.themePicker() - @QtCore.pyqtSlot(QtGui.QSystemTrayIcon.ActivationReason) + @QtCore.pyqtSlot(QtWidgets.QSystemTrayIcon.ActivationReason) def systemTrayActivated(self, reason): - if reason == QtGui.QSystemTrayIcon.Trigger: + if reason == QtWidgets.QSystemTrayIcon.Trigger: self.systemTrayFunction() - elif reason == QtGui.QSystemTrayIcon.Context: + elif reason == QtWidgets.QSystemTrayIcon.Context: pass # show context menu i guess #self.showTrayContext.emit() @QtCore.pyqtSlot() def tooManyPeeps(self): - msg = QtGui.QMessageBox(self) + msg = QtWidgets.QMessageBox(self) msg.setText("D: TOO MANY PEOPLE!!!") msg.setInformativeText("The server has hit max capacity. Please try again later.") msg.show() - pcUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) + pcUpdate = QtCore.pyqtSignal('QString', 'QString') closeToTraySignal = QtCore.pyqtSignal() - newConvoStarted = QtCore.pyqtSignal(QtCore.QString, bool, name="newConvoStarted") - sendMessage = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - sendNotice = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - convoClosed = QtCore.pyqtSignal(QtCore.QString) + newConvoStarted = QtCore.pyqtSignal('QString', bool, name="newConvoStarted") + sendMessage = QtCore.pyqtSignal('QString', 'QString') + sendNotice = QtCore.pyqtSignal('QString', 'QString') + convoClosed = QtCore.pyqtSignal('QString') profileChanged = QtCore.pyqtSignal() animationSetting = QtCore.pyqtSignal(bool) moodRequest = QtCore.pyqtSignal(PesterProfile) moodsRequest = QtCore.pyqtSignal(PesterList) moodUpdated = QtCore.pyqtSignal() requestChannelList = QtCore.pyqtSignal() - requestNames = QtCore.pyqtSignal(QtCore.QString) - namesUpdated = QtCore.pyqtSignal(QtCore.QString) - modesUpdated = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - userPresentSignal = QtCore.pyqtSignal(QtCore.QString,QtCore.QString,QtCore.QString) + requestNames = QtCore.pyqtSignal('QString') + namesUpdated = QtCore.pyqtSignal('QString') + modesUpdated = QtCore.pyqtSignal('QString', 'QString') + userPresentSignal = QtCore.pyqtSignal('QString','QString','QString') mycolorUpdated = QtCore.pyqtSignal() trayIconSignal = QtCore.pyqtSignal(int) - blockedChum = QtCore.pyqtSignal(QtCore.QString) - unblockedChum = QtCore.pyqtSignal(QtCore.QString) - kickUser = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - joinChannel = QtCore.pyqtSignal(QtCore.QString) - leftChannel = QtCore.pyqtSignal(QtCore.QString) - setChannelMode = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString) - channelNames = QtCore.pyqtSignal(QtCore.QString) - inviteChum = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - inviteOnlyChan = QtCore.pyqtSignal(QtCore.QString) + blockedChum = QtCore.pyqtSignal('QString') + unblockedChum = QtCore.pyqtSignal('QString') + kickUser = QtCore.pyqtSignal('QString', 'QString') + joinChannel = QtCore.pyqtSignal('QString') + leftChannel = QtCore.pyqtSignal('QString') + setChannelMode = QtCore.pyqtSignal('QString', 'QString', 'QString') + channelNames = QtCore.pyqtSignal('QString') + inviteChum = QtCore.pyqtSignal('QString', 'QString') + inviteOnlyChan = QtCore.pyqtSignal('QString') closeSignal = QtCore.pyqtSignal() reconnectIRC = QtCore.pyqtSignal() - gainAttention = QtCore.pyqtSignal(QtGui.QWidget) + gainAttention = QtCore.pyqtSignal(QtWidgets.QWidget) pingServer = QtCore.pyqtSignal() setAway = QtCore.pyqtSignal(bool) - killSomeQuirks = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) + killSomeQuirks = QtCore.pyqtSignal('QString', 'QString') -class PesterTray(QtGui.QSystemTrayIcon): +class PesterTray(QtWidgets.QSystemTrayIcon): def __init__(self, icon, mainwindow, parent): super(PesterTray, self).__init__(icon, parent) self.mainwindow = mainwindow @@ -3031,7 +2950,7 @@ class MainProgram(QtCore.QObject): # See http://stackoverflow.com/a/1552105 for more details. from ctypes import windll # Note that this has to be unicode. - wid = u"mspa.homestuck.pesterchum.314" + wid = "mspa.homestuck.pesterchum.314" # Designate this as a separate process - i.e., tell Windows that # Python is just hosting Pesterchum. # TODO: Eventually we should get this changed so it checks and @@ -3045,7 +2964,7 @@ class MainProgram(QtCore.QObject): logging.error("Attempted to set as {0!r}.".format(wid)) # Back to our scheduled program. - self.app = QtGui.QApplication(sys.argv) + self.app = QtWidgets.QApplication(sys.argv) self.app.setApplicationName("Pesterchum 3.14") self.app.setQuitOnLastWindowClosed(False) @@ -3071,7 +2990,7 @@ class MainProgram(QtCore.QObject): except: pass self.server = "irc.pesterchum.xyz" - print("Server is: " + self.server) + print(("Server is: " + self.server)) def doSoundInit(): # TODO: Make this more uniform, adapt it into a general function. @@ -3081,7 +3000,7 @@ class MainProgram(QtCore.QObject): pygame.mixer.init() pygame.mixer.init() except pygame.error as err: - print "Warning: No sound! (pygame error: %s)" % err + print("Warning: No sound! (pygame error: %s)" % err) else: # Sound works, we're done. return @@ -3089,61 +3008,43 @@ class MainProgram(QtCore.QObject): # ... Other alternatives here. ... # Last resort. (Always 'works' on Windows, no volume control.) - if QtGui.QSound.isAvailable(): + if QtMultimedia.QSound.isAvailable(): # Sound works, we're done. return else: - print "Warning: No sound! (No pygame/QSound)" + print("Warning: No sound! (No pygame/QSound)") doSoundInit() self.widget = PesterWindow(options, app=self.app) self.widget.show() self.trayicon = PesterTray(PesterIcon(self.widget.theme["main/icon"]), self.widget, self.app) - self.traymenu = QtGui.QMenu() + self.traymenu = QtWidgets.QMenu() moodMenu = self.traymenu.addMenu("SET MOOD") moodCategories = {} for k in Mood.moodcats: moodCategories[k] = moodMenu.addMenu(k.upper()) self.moodactions = {} for (i,m) in enumerate(Mood.moods): - maction = QtGui.QAction(m.upper(), self) + maction = QtWidgets.QAction(m.upper(), self) mobj = PesterMoodAction(i, self.widget.moods.updateMood) - self.trayicon.connect(maction, QtCore.SIGNAL('triggered()'), - mobj, QtCore.SLOT('updateMood()')) + maction.triggered.connect(mobj.updateMood) self.moodactions[i] = mobj moodCategories[Mood.revmoodcats[m]].addAction(maction) - miniAction = QtGui.QAction("MINIMIZE", self) - self.trayicon.connect(miniAction, QtCore.SIGNAL('triggered()'), - self.widget, QtCore.SLOT('showMinimized()')) - exitAction = QtGui.QAction("EXIT", self) - self.trayicon.connect(exitAction, QtCore.SIGNAL('triggered()'), - self.app, QtCore.SLOT('quit()')) + miniAction = QtWidgets.QAction("MINIMIZE", self) + miniAction.triggered.connect(self.widget.showMinimized) + exitAction = QtWidgets.QAction("EXIT", self) + exitAction.triggered.connect(self.app.quit) self.traymenu.addAction(miniAction) self.traymenu.addAction(exitAction) self.trayicon.setContextMenu(self.traymenu) self.trayicon.show() - self.trayicon.connect(self.trayicon, - QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), - self.widget, - QtCore.SLOT('systemTrayActivated(QSystemTrayIcon::ActivationReason)')) - self.trayicon.connect(self.widget, - QtCore.SIGNAL('trayIconSignal(int)'), - self.trayicon, - QtCore.SLOT('changeTrayIcon(int)')) - self.trayicon.connect(self.widget, - QtCore.SIGNAL('closeToTraySignal()'), - self, - QtCore.SLOT('trayiconShow()')) - self.trayicon.connect(self.widget, - QtCore.SIGNAL('closeSignal()'), - self.trayicon, - QtCore.SLOT('mainWindowClosed()')) - self.connect(self.trayicon, - QtCore.SIGNAL('messageClicked()'), - self, - QtCore.SLOT('trayMessageClick()')) + self.trayicon.activated[QSystemTrayIcon.ActivationReason].connect(self.widget.systemTrayActivated) + self.widget.trayIconSignal[int].connect(self.trayicon.changeTrayIcon) + self.widget.closeToTraySignal.connect(self.trayiconShow) + self.widget.closeSignal.connect(self.trayicon.mainWindowClosed) + self.trayicon.messageClicked.connect(self.trayMessageClick) self.attempts = 0 @@ -3152,8 +3053,7 @@ class MainProgram(QtCore.QObject): self.irc = PesterIRC(self.widget.config, self.widget, self.server) self.connectWidgets(self.irc, self.widget) - self.connect(self.widget, QtCore.SIGNAL('gainAttention(QWidget*)'), - self, QtCore.SLOT('alertWindow(QWidget*)')) + self.widget.gainAttention[QWidget].connect(self.alertWindow) # This doesn't know as far as I'm aware, so it's commented out for now. @@ -3180,7 +3080,7 @@ class MainProgram(QtCore.QObject): @QtCore.pyqtSlot() def runUpdateSlot(self): - q = Queue.Queue(1) + q = queue.Queue(1) s = threading.Thread(target=version.updateCheck, args=(q,)) w = threading.Thread(target=self.showUpdate, args=(q,)) w.start() @@ -3195,7 +3095,7 @@ class MainProgram(QtCore.QObject): return QtCore.QTimer.singleShot(1000*seconds, self, QtCore.SLOT('runUpdateSlot()')) - @QtCore.pyqtSlot(QtGui.QWidget) + @QtCore.pyqtSlot(QtWidgets.QWidget) def alertWindow(self, widget): self.app.alert(widget) @@ -3285,27 +3185,19 @@ Click this message to never see this again.") 'quirkDisable(QString, QString, QString)') ] def connectWidgets(self, irc, widget): - self.connect(irc, QtCore.SIGNAL('finished()'), - self, QtCore.SLOT('restartIRC()')) - self.connect(irc, QtCore.SIGNAL('connected()'), - self, QtCore.SLOT('connected()')) + irc.finished.connect(self.restartIRC) + irc.connected.connect(self.connected) for c in self.widget2irc: - self.connect(widget, QtCore.SIGNAL(c[0]), - irc, QtCore.SLOT(c[1])) + widget.c[0].connect(irc.c[1]) for c in self.irc2widget: - self.connect(irc, QtCore.SIGNAL(c[0]), - widget, QtCore.SLOT(c[1])) + irc.c[0].connect(widget.c[1]) def disconnectWidgets(self, irc, widget): for c in self.widget2irc: - self.disconnect(widget, QtCore.SIGNAL(c[0]), - irc, QtCore.SLOT(c[1])) + widget.c[0].disconnect(irc.c[1]) for c in self.irc2widget: - self.disconnect(irc, QtCore.SIGNAL(c[0]), - widget, QtCore.SLOT(c[1])) - self.disconnect(irc, QtCore.SIGNAL('connected()'), - self, QtCore.SLOT('connected()')) - self.disconnect(self.irc, QtCore.SIGNAL('finished()'), - self, QtCore.SLOT('restartIRC()')) + irc.c[0].disconnect(widget.c[1]) + irc.connected.disconnect(self.connected) + self.irc.finished.disconnect(self.restartIRC) def showUpdate(self, q): new_url = q.get() @@ -3335,10 +3227,8 @@ Click this message to never see this again.") else: widget.loadingscreen = LoadingScreen(widget) widget.loadingscreen.loadinglabel.setText(msg) - self.connect(widget.loadingscreen, QtCore.SIGNAL('rejected()'), - widget.app, QtCore.SLOT('quit()')) - self.connect(self.widget.loadingscreen, QtCore.SIGNAL('tryAgain()'), - self, QtCore.SLOT('tryAgain()')) + widget.loadingscreen.rejected.connect(widget.app.quit) + self.widget.loadingscreen.tryAgain.connect(self.tryAgain) if hasattr(self, 'irc') and self.irc.registeredIRC: return if self.reconnectok: @@ -3346,14 +3236,14 @@ Click this message to never see this again.") else: widget.loadingscreen.hideReconnect() status = widget.loadingscreen.exec_() - if status == QtGui.QDialog.Rejected: + if status == QtWidgets.QDialog.Rejected: sys.exit(0) else: if self.widget.tabmemo: for c in self.widget.tabmemo.convos: self.irc.joinChannel(c) else: - for c in self.widget.memos.values(): + for c in list(self.widget.memos.values()): self.irc.joinChannel(c.channel) return True @@ -3365,7 +3255,7 @@ Click this message to never see this again.") if not self.reconnectok: return if self.widget.loadingscreen: - self.widget.loadingscreen.done(QtGui.QDialog.Accepted) + self.widget.loadingscreen.done(QtWidgets.QDialog.Accepted) self.widget.loadingscreen = None self.attempts += 1 if hasattr(self, 'irc') and self.irc: diff --git a/pnc/dep/attrdict.py b/pnc/dep/attrdict.py index fc0b9bb..c8a1bb4 100644 --- a/pnc/dep/attrdict.py +++ b/pnc/dep/attrdict.py @@ -13,7 +13,7 @@ class AttrDict(dict): super(AttrDict, self).__init__(init) def __getstate__(self): - return self.__dict__.items() + return list(self.__dict__.items()) def __setstate__(self, items): for key, val in items: self.__dict__[key] = val diff --git a/pnc/lexercon.py b/pnc/lexercon.py index 81891c9..0b979b0 100644 --- a/pnc/lexercon.py +++ b/pnc/lexercon.py @@ -1,5 +1,5 @@ # -*- coding=UTF-8; tab-width: 4 -*- -from __future__ import division + from .unicolor import Color @@ -8,7 +8,7 @@ import re global basestr basestr = str try: - basestr = basestring + basestr = str except NameError: # We're running Python 3. Leave it be. pass @@ -160,7 +160,7 @@ class CTag(Specifier): cmatch = Pesterchum._ctag_rgb.match(text) if cmatch: working = cmatch.groups() - working = map(int, working) + working = list(map(int, working)) inst.color = Color(*working) else: try: diff --git a/pnc/unicolor.py b/pnc/unicolor.py index af50120..e7ee0e7 100644 --- a/pnc/unicolor.py +++ b/pnc/unicolor.py @@ -1,5 +1,5 @@ # -*- coding=UTF-8; tab-width: 4 -*- -from __future__ import division + __all__ = ["Color"] @@ -16,7 +16,7 @@ import sys # Python 3 checking if sys.version_info[0] == 2: - basestr = basestring + basestr = str else: basestr = str @@ -119,7 +119,7 @@ class Color(object): ## self.red, self.green, self.blue ## ]) # 2012-12-08T13:34-07:00: This should improve accuracy - result = map(hash, self.cielab) + result = list(map(hash, self.cielab)) result = functools.reduce(lambda x, y: x ^ y, result) return result @@ -201,7 +201,7 @@ class Color(object): closest, cldist = None, None targs = _irc_colors - for code, other in targs.items(): + for code, other in list(targs.items()): dist = self - other ##if (not strict and dist > self.jnd) or dist == 0: if dist == 0: @@ -217,7 +217,7 @@ class Color(object): closest, cldist = None, None targs = _svg_colors - for name, other in targs.items(): + for name, other in list(targs.items()): dist = self - other if (not strict and dist > self.jnd) or dist == 0: # The difference is below the Just-Noticeable Difference @@ -236,7 +236,7 @@ class Color(object): # http://en.wikipedia.org/wiki/Color_difference slab, olab = self.to_cielab_tuple(), other.to_cielab_tuple() # Calculate the distance between the points for each - dist = map(lambda p1, p2: (p2 - p1)**2, slab, olab) + dist = list(map(lambda p1, p2: (p2 - p1)**2, slab, olab)) # Add the results up, and sqrt to compensate for earlier squaring dist = sum(dist) ** .5 return dist @@ -252,7 +252,7 @@ class Color(object): ### Square the results from the above ##dist = [x**2 for x in dist] # Do what we WOULD have done in those two lines with a single one - dist = map(lambda x1, x2: (x1 - x2)**2, srgb, orgb) + dist = list(map(lambda x1, x2: (x1 - x2)**2, srgb, orgb)) # Add the results up dist = sum(dist) # Fetch the square root to compensate for the earlier squaring @@ -284,7 +284,7 @@ class Color(object): @staticmethod def rgb_to_hexstr(red, green, blue, compress=False): rgb = [red, green, blue] - rgb = map(abs, rgb) + rgb = list(map(abs, rgb)) result = [] for c in rgb: c = "%02X" % c @@ -547,7 +547,7 @@ _svg_colors.update({ "yellow": Color(255, 255, 0), "yellowgreen": Color(154, 205, 50) }) -for k, v in _svg_colors.items(): +for k, v in list(_svg_colors.items()): v.closest_name = v.name = k # 2012-12-08T14:29-07:00: Copied over from Colors.hexstr_for_ccodes in the main @@ -594,7 +594,7 @@ _irc_colors.update({ 99: Color(0x999999) # Until I think of a better solution to this }) -for k, v in _irc_colors.items(): +for k, v in list(_irc_colors.items()): v.ccode = "%02d" % k del k, v diff --git a/profile.py b/profile.py index d9498db..32cf576 100644 --- a/profile.py +++ b/profile.py @@ -7,7 +7,7 @@ import codecs import platform from datetime import * from time import strftime, time -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets import ostools from mood import Mood @@ -48,22 +48,22 @@ class PesterLog(object): html = time + convertTags(msg, "html")+"
" msg = time +convertTags(msg, "text") modes = {"bbcode": bbcodemsg, "html": html, "text": msg} - if not self.convos.has_key(handle): + if handle not in self.convos: time = datetime.now().strftime("%Y-%m-%d.%H.%M") self.convos[handle] = {} - for (format, t) in modes.iteritems(): + for (format, t) in modes.items(): if not os.path.exists("%s/%s/%s/%s" % (self.logpath, self.handle, handle, format)): os.makedirs("%s/%s/%s/%s" % (self.logpath, self.handle, handle, format)) try: fp = codecs.open("%s/%s/%s/%s/%s.%s.txt" % (self.logpath, self.handle, handle, format, handle, time), encoding='utf-8', mode='a') except IOError: - errmsg = QtGui.QMessageBox(self) + errmsg = QtWidgets.QMessageBox(self) errmsg.setText("Warning: Pesterchum could not open the log file for %s!" % (handle)) errmsg.setInformativeText("Your log for %s will not be saved because something went wrong. We suggest restarting Pesterchum. Sorry :(" % (handle)) errmsg.show() continue self.convos[handle][format] = fp - for (format, t) in modes.iteritems(): + for (format, t) in modes.items(): f = self.convos[handle][format] if platform.system() == "Windows": f.write(t+"\r\n") @@ -71,14 +71,14 @@ class PesterLog(object): f.write(t+"\r\n") f.flush() def finish(self, handle): - if not self.convos.has_key(handle): + if handle not in self.convos: return - for f in self.convos[handle].values(): + for f in list(self.convos[handle].values()): f.close() del self.convos[handle] def close(self): - for h in self.convos.keys(): - for f in self.convos[h].values(): + for h in list(self.convos.keys()): + for f in list(self.convos[h].values()): f.close() class userConfig(object): @@ -104,7 +104,7 @@ class userConfig(object): # No such file or directory: # u'XXX\\AppData\\Local\\pesterchum/profiles/XXX.js' # Part 2 :( - if self.config.has_key("defaultprofile"): + if "defaultprofile" in self.config: try: self.userprofile = userProfile(self.config["defaultprofile"]) except: @@ -125,7 +125,7 @@ class userConfig(object): json.dump(self.groups, fp) def chums(self): - if not self.config.has_key('chums'): + if 'chums' not in self.config: self.set("chums", []) return self.config.get('chums', []) def setChums(self, newchums): @@ -148,19 +148,19 @@ class userConfig(object): def tabs(self): return self.config.get("tabs", True) def tabMemos(self): - if not self.config.has_key('tabmemos'): + if 'tabmemos' not in self.config: self.set("tabmemos", self.tabs()) return self.config.get("tabmemos", True) def showTimeStamps(self): - if not self.config.has_key('showTimeStamps'): + if 'showTimeStamps' not in self.config: self.set("showTimeStamps", True) return self.config.get('showTimeStamps', True) def time12Format(self): - if not self.config.has_key('time12Format'): + if 'time12Format' not in self.config: self.set("time12Format", True) return self.config.get('time12Format', True) def showSeconds(self): - if not self.config.has_key('showSeconds'): + if 'showSeconds' not in self.config: self.set("showSeconds", False) return self.config.get('showSeconds', False) def sortMethod(self): @@ -174,11 +174,11 @@ class userConfig(object): return g[1] return True def showEmptyGroups(self): - if not self.config.has_key('emptyGroups'): + if 'emptyGroups' not in self.config: self.set("emptyGroups", False) return self.config.get('emptyGroups', False) def showOnlineNumbers(self): - if not self.config.has_key('onlineNumbers'): + if 'onlineNumbers' not in self.config: self.set("onlineNumbers", False) return self.config.get('onlineNumbers', False) def logPesters(self): @@ -238,7 +238,7 @@ class userConfig(object): newchums = [c for c in self.config['chums'] if c != handle] self.set("chums", newchums) def getBlocklist(self): - if not self.config.has_key('block'): + if 'block' not in self.config: self.set('block', []) return self.config['block'] def addBlocklist(self, handle): @@ -251,7 +251,7 @@ class userConfig(object): l.pop(l.index(handle)) self.set('block', l) def getGroups(self): - if not self.groups.has_key('groups'): + if 'groups' not in self.groups: self.saveGroups([["Chums", True]]) return self.groups.get('groups', [["Chums", True]]) def addGroup(self, group, open=True): @@ -301,7 +301,7 @@ class userConfig(object): return self.parent.portOverride return self.config.get('port', '6667') def soundOn(self): - if not self.config.has_key('soundon'): + if 'soundon' not in self.config: self.set('soundon', True) return self.config['soundon'] def chatSound(self): @@ -356,7 +356,7 @@ class userProfile(object): if type(user) is PesterProfile: self.chat = user self.userprofile = {"handle":user.handle, - "color": unicode(user.color.name()), + "color": str(user.color.name()), "quirks": [], "theme": "pesterchum"} self.theme = pesterTheme("pesterchum") @@ -382,8 +382,8 @@ class userProfile(object): self.userprofile = json.load(fp) except: - msgBox = QtGui.QMessageBox() - msgBox.setIcon(QtGui.QMessageBox.Information) + msgBox = QtWidgets.QMessageBox() + msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setWindowTitle(":(") self.filename = _datadir+"pesterchum.js" msgBox.setText("Failed to open \"" + \ @@ -449,7 +449,7 @@ class userProfile(object): self.save() def setColor(self, color): self.chat.color = color - self.userprofile["color"] = unicode(color.name()) + self.userprofile["color"] = str(color.name()) self.save() def setQuirks(self, quirks): self.quirks = quirks @@ -467,7 +467,7 @@ class userProfile(object): try: for (i,m) in enumerate(mentions): re.compile(m) - except re.error, e: + except re.error as e: logging.error("#%s Not a valid regular expression: %s" % (i, e)) else: self.mentions = mentions @@ -516,7 +516,7 @@ class userProfile(object): fp.write(jsonoutput) def saveNickServPass(self): # remove profiles with no passwords - for h,t in self.passwd.items(): + for h,t in list(self.passwd.items()): if "auto" not in t and ("pw" not in t or t["pw"] == ""): del self.passwd[h] try: @@ -550,7 +550,7 @@ class PesterProfileDB(dict): json.dump(chumdict, fp) u = [] - for (handle, c) in chumdict.iteritems(): + for (handle, c) in chumdict.items(): options = dict() if 'group' in c: options['group'] = c['group'] @@ -567,38 +567,38 @@ class PesterProfileDB(dict): def save(self): try: with open("%s/chums.js" % (self.logpath), 'w') as fp: - chumdict = dict([p.plaindict() for p in self.itervalues()]) + chumdict = dict([p.plaindict() for p in self.values()]) json.dump(chumdict, fp) except Exception as e: raise e def getColor(self, handle, default=None): - if not self.has_key(handle): + if handle not in self: return default else: return self[handle].color def setColor(self, handle, color): - if self.has_key(handle): + if handle in self: self[handle].color = color else: self[handle] = PesterProfile(handle, color) def getGroup(self, handle, default="Chums"): - if not self.has_key(handle): + if handle not in self: return default else: return self[handle].group def setGroup(self, handle, theGroup): - if self.has_key(handle): + if handle in self: self[handle].group = theGroup else: self[handle] = PesterProfile(handle, group=theGroup) self.save() def getNotes(self, handle, default=""): - if not self.has_key(handle): + if handle not in self: return default else: return self[handle].notes def setNotes(self, handle, notes): - if self.has_key(handle): + if handle in self: self[handle].notes = notes else: self[handle] = PesterProfile(handle, notes=notes) @@ -626,7 +626,7 @@ class pesterTheme(dict): except IOError: theme = json.loads("{}") self.update(theme) - if self.has_key("inherits"): + if "inherits" in self: self.inheritedTheme = pesterTheme(self["inherits"]) if not default: self.defaultTheme = pesterTheme("pesterchum", default=True) @@ -653,8 +653,8 @@ class pesterTheme(dict): raise e return v def pathHook(self, d): - for (k, v) in d.iteritems(): - if isinstance(v, unicode): + for (k, v) in d.items(): + if isinstance(v, str): s = Template(v) d[k] = s.safe_substitute(path=self.path) return d @@ -680,6 +680,6 @@ class pesterTheme(dict): return (v is not None) except KeyError: if hasattr(self, 'inheritedTheme'): - return self.inheritedTheme.has_key(key) + return key in self.inheritedTheme else: return False diff --git a/py2app.sh b/py2app.sh deleted file mode 100755 index bb413a4..0000000 --- a/py2app.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/bin/bash - -## Cleanup -rm -rf build/ dist/ -rm -f Pesterchum.dmg - -### Force build with custom installed frameworky python not system python -/Library/Frameworks/Python.framework/Versions/2.6/bin/python setup-py2app.py py2app -#python setup-py2app.py py2app -# -### Do some .app tings -touch dist/Pesterchum.app/Contents/Resources/qt.conf -find dist/Pesterchum.app -iname "*_debug" -exec rm -f '{}' \; - -## Create a dmg file to hold everything -VERSION=$(python version.py) #"3.41.2 Beta 5" -SIZE=2000 -name="Pesterchum" -title="${name} ${VERSION}" -CHANGELOG="Changelog.rtf" -PYQUIRKS="Python Quirks.rtf" -TODO="To Do.rtf" -README="Read Me!.rtf" -## Make a proper installer dmg not just effectively a zip file. -# -# Most of this is from http://stackoverflow.com/questions/96882/ -# I've fiddled with it a little - -# Store the background picture (in PNG format) in a folder called ".background" -# in the DMG, and store its name in the "backgroundPictureName" variable. - -mkdir dist/.background -cp MacBuild/dmg_background.png dist/.background/display.png - -# Convert markdown files to rich text files -convert=~/Library/Haskell/bin/pandoc -if ! test -e "${convert}" -then - echo "Please install pandoc from http://johnmacfarlane.net/pandoc/" 1>&2 - exit 1 -fi - -echo "Converting CHANGELOG . . . " -$convert --standalone --smart --from=markdown --to=rtf --output="dist/${CHANGELOG}" CHANGELOG.mkdn -echo "Converting PYQUIRKS . . ." -$convert --standalone --smart --from=markdown --to=rtf --output="dist/${PYQUIRKS}" PYQUIRKS.mkdn -echo "Converting TODO . . ." -$convert --standalone --smart --from=markdown --to=rtf --output="dist/${TODO}" TODO.mkdn -echo "Converting README . . ." -$convert --standalone --smart --from=markdown --to=rtf --output="dist/${README}" README.mkdn - -# Create a R/W DMG. It must be larger than the result will be. -# In this example, the bash variable "size" contains the size -# in Kb and the contents of the folder in the "source" bash -# variable will be copied into the DMG: -# Note: I've removed the size argument - -echo "Creating initial DMG file . . ." -hdiutil create -srcfolder "./dist" -volname "${title}" -fs HFS+ \ - -fsargs "-c c=64,a=16,e=16" -format UDRW pack.temp.dmg - -# Mount the disk image, and store the device name -# (you might want to use sleep for a few seconds after this operation): - -echo "Mounting initial DMG file . . ." -device=$(hdiutil attach -readwrite -noverify -noautoopen "pack.temp.dmg" | \ - egrep '^/dev/' | sed 1q | awk '{print $1}') -sleep 2 - - - -# Use AppleScript to set the visual styles (name of .app must be in bash variable -# "applicationName", use variables for the other properties as needed): -base=100 -iconsize=72 -padding=18 -echo "Making DMG file pretty with Applescript . . ." -echo ' - tell application "Finder" - tell disk "'${title}'" - open - set current view of container window to icon view - set toolbar visible of container window to false - set statusbar visible of container window to false - set the bounds of container window to {400, 100, 885, 430} - set theViewOptions to the icon view options of container window - set arrangement of theViewOptions to not arranged - set icon size of theViewOptions to 72 - set background picture of theViewOptions to file ".background:display.png" - make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} - -- Positions - set position of item "'${name}'.app" of container window to {100, 100} - set position of item "Applications" of container window to {375, 100} - set position of item "'${README}'" of container window to {'${base}+${iconsize}*0+${padding}*0', 244} - set position of item "'${CHANGELOG}'" of container window to {'${base}+${iconsize}*1+${padding}*1', 244} - set position of item "'${PYQUIRKS}'" of container window to {'${base}+${iconsize}*2+${padding}*2', 244} - set position of item "'${TODO}'" of container window to {'${base}+${iconsize}*3+${padding}*3', 244} - -- Visibility - set extension hidden of item "'${CHANGELOG}'" of container window to true - set extension hidden of item "'${PYQUIRKS}'" of container window to true - set extension hidden of item "'${TODO}'" of container window to true - set extension hidden of item "'${README}'" of container window to true - close - open - update without registering applications - delay 5 - eject - end tell - end tell -' | osascript - -# This took so long to work out how to do ._. -# Stolen from http://lists.apple.com/archives/darwin-userlevel/2007/Oct/msg00000.html -# Set the SLA to read only (dunno why) -echo "Converting initial DMG file to a UDRO one . . ." -hdiutil convert -ov -format UDRO -o "sla.temp.dmg" "pack.temp.dmg" -# Inflate the dmg -echo "Inflating UDRO DMG file . . ." -hdiutil unflatten "sla.temp.dmg" -# Attach the GPL -echo "Attaching GPL licence . . ." -Rez -a MacBuild/GPL.res -o "sla.temp.dmg" -# Steamroller again -echo "Deflating UDRO DMG file . . ." -hdiutil flatten "sla.temp.dmg" - -# Finialize the DMG by setting permissions properly, compressing and releasing it: - -#chmod -Rf go-w /Volumes/"${title}" -sync -#hdiutil detach ${device} -echo "Compressing UDRO DMG file to UDZO for release . . ." -hdiutil convert "sla.temp.dmg" -format UDZO -imagekey zlib-level=6 -o "${name}.dmg" - -# Get rid of the bits -echo "Cleaning up . . ." -rm -f pack.temp.dmg -rm -f sla.temp.dmg -rm -rf build/ dist/ diff --git a/pyquirks.py b/pyquirks.py index 8ecf999..19f256e 100644 --- a/pyquirks.py +++ b/pyquirks.py @@ -1,6 +1,6 @@ import os, sys, imp, re, ostools from quirks import ScriptQuirks -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets class PythonQuirks(ScriptQuirks): def loadModule(self, name, filename): @@ -12,21 +12,21 @@ class PythonQuirks(ScriptQuirks): def modHas(self, module, attr): if attr == 'commands': variables = vars(module) - for name, obj in variables.iteritems(): + for name, obj in variables.items(): if self.modHas(obj, 'command'): return True return hasattr(module, attr) def register(self, module): variables = vars(module) - for name, obj in variables.iteritems(): + for name, obj in variables.items(): if self.modHas(obj, 'command'): try: - if not isinstance(obj("test"), basestring): + if not isinstance(obj("test"), str): raise Exception except: - print "Quirk malformed: %s" % (obj.command) - msgbox = QtGui.QMessageBox() + print("Quirk malformed: %s" % (obj.command)) + msgbox = QtWidgets.QMessageBox() msgbox.setWindowTitle("Error!") msgbox.setText("Quirk malformed: %s" % (obj.command)) msgbox.exec_() diff --git a/quirks.py b/quirks.py index 48e3b85..9f32246 100644 --- a/quirks.py +++ b/quirks.py @@ -1,5 +1,5 @@ import os, sys, re, ostools -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets class ScriptQuirks(object): def __init__(self): @@ -20,7 +20,7 @@ class ScriptQuirks(object): self.last = self.quirks.copy() self.quirks.clear() for script in self.scripts: - print script.getExtension() + print(script.getExtension()) script.load() #print script.quirks for q in script.quirks: @@ -31,9 +31,9 @@ class ScriptQuirks(object): del self.quirks[k] #print self.quirks if self.quirks: - print 'Registered quirks:', '(), '.join(self.quirks) + "()" + print('Registered quirks:', '(), '.join(self.quirks) + "()") else: - print "Warning: Couldn't find any script quirks" + print("Warning: Couldn't find any script quirks") def add(self, script): self.scripts.append(script) @@ -65,8 +65,8 @@ class ScriptQuirks(object): if module is None: continue except Exception as e: - print "Error loading %s: %s (in quirks.py)" % (os.path.basename(name), e) - msgbox = QtGui.QMessageBox() + print("Error loading %s: %s (in quirks.py)" % (os.path.basename(name), e)) + msgbox = QtWidgets.QMessageBox() msgbox.setWindowTitle("Error!") msgbox.setText("Error loading %s: %s (in quirks.py)" % (os.path.basename(filename), e)) msgbox.exec_() diff --git a/quirks/example.lua b/quirks/example.lua deleted file mode 100644 index 82f8045..0000000 --- a/quirks/example.lua +++ /dev/null @@ -1,18 +0,0 @@ -module(..., package.seeall) -commands = {} - -local function upper(text) - return string.upper(text) -end -commands.luaupper = upper - -local function lower(text) - return string.lower(text) -end -commands.lualower = lower - -local function utf8reverse(text) - return text:gsub("([\194-\244][\128-\191]+)", string.reverse):reverse() -end -commands.luareverse = utf8reverse - diff --git a/randomer.py b/randomer.py index ff62399..511128e 100644 --- a/randomer.py +++ b/randomer.py @@ -1,4 +1,4 @@ -from PyQt4 import QtGui, QtCore +from PyQt5 import QtCore, QtGui, QtWidgets RANDNICK = "randomEncounter" @@ -58,12 +58,12 @@ class RandomHandler(QtCore.QObject): pass elif code == "!": if l[1] == "x": - from PyQt4 import QtGui - msgbox = QtGui.QMessageBox() + from PyQt5 import QtGui, QtWidgets + msgbox = QtWidgets.QMessageBox() msgbox.setText("Unable to fetch you a random encounter!") msgbox.setInformativeText("Try again later :(") msgbox.exec_() return - name = unicode(l[1]) - print name + name = str(l[1]) + print(name) self.mainwindow.newConversation(name) diff --git a/server.json b/server.json deleted file mode 100644 index fce98d0..0000000 --- a/server.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "server": "pesterchum.xyz" -} \ No newline at end of file diff --git a/smilies/Suckers.gif b/smilies/Suckers.gif deleted file mode 100644 index ff5a89f..0000000 Binary files a/smilies/Suckers.gif and /dev/null differ diff --git a/smilies/acceptant.png b/smilies/acceptant.png deleted file mode 100644 index 163ee04..0000000 Binary files a/smilies/acceptant.png and /dev/null differ diff --git a/smilies/apple.png b/smilies/apple.png deleted file mode 100644 index b1462d9..0000000 Binary files a/smilies/apple.png and /dev/null differ diff --git a/smilies/bathearst.png b/smilies/bathearst.png deleted file mode 100644 index e47162f..0000000 Binary files a/smilies/bathearst.png and /dev/null differ diff --git a/smilies/blacktear.png b/smilies/blacktear.png deleted file mode 100644 index 8c91ad8..0000000 Binary files a/smilies/blacktear.png and /dev/null differ diff --git a/smilies/blueslimer.gif b/smilies/blueslimer.gif deleted file mode 100644 index 7a2f8eb..0000000 Binary files a/smilies/blueslimer.gif and /dev/null differ diff --git a/smilies/blueslimer.png b/smilies/blueslimer.png deleted file mode 100644 index 4db51ec..0000000 Binary files a/smilies/blueslimer.png and /dev/null differ diff --git a/smilies/box.png b/smilies/box.png deleted file mode 100644 index 8443c23..0000000 Binary files a/smilies/box.png and /dev/null differ diff --git a/smilies/candycorn.png b/smilies/candycorn.png deleted file mode 100644 index 6ca85c5..0000000 Binary files a/smilies/candycorn.png and /dev/null differ diff --git a/smilies/cathearst.png b/smilies/cathearst.png deleted file mode 100644 index 82fca88..0000000 Binary files a/smilies/cathearst.png and /dev/null differ diff --git a/smilies/cheer.gif b/smilies/cheer.gif deleted file mode 100644 index 8d2c8cd..0000000 Binary files a/smilies/cheer.gif and /dev/null differ diff --git a/smilies/cheer.png b/smilies/cheer.png deleted file mode 100644 index 16d3b8f..0000000 Binary files a/smilies/cheer.png and /dev/null differ diff --git a/smilies/confusedjohn.gif b/smilies/confusedjohn.gif deleted file mode 100644 index 9298353..0000000 Binary files a/smilies/confusedjohn.gif and /dev/null differ diff --git a/smilies/confusedjohn.png b/smilies/confusedjohn.png deleted file mode 100644 index 2bc5e43..0000000 Binary files a/smilies/confusedjohn.png and /dev/null differ diff --git a/smilies/datrump.png b/smilies/datrump.png deleted file mode 100644 index af259b4..0000000 Binary files a/smilies/datrump.png and /dev/null differ diff --git a/smilies/detestful.png b/smilies/detestful.png deleted file mode 100644 index dc573df..0000000 Binary files a/smilies/detestful.png and /dev/null differ diff --git a/smilies/devious.png b/smilies/devious.png deleted file mode 100644 index eae4799..0000000 Binary files a/smilies/devious.png and /dev/null differ diff --git a/smilies/discontent.png b/smilies/discontent.png deleted file mode 100644 index 546a2eb..0000000 Binary files a/smilies/discontent.png and /dev/null differ diff --git a/smilies/distraught.png b/smilies/distraught.png deleted file mode 100644 index c923891..0000000 Binary files a/smilies/distraught.png and /dev/null differ diff --git a/smilies/ecstatic.png b/smilies/ecstatic.png deleted file mode 100644 index edb062e..0000000 Binary files a/smilies/ecstatic.png and /dev/null differ diff --git a/smilies/facepalm.png b/smilies/facepalm.png deleted file mode 100644 index e5bc561..0000000 Binary files a/smilies/facepalm.png and /dev/null differ diff --git a/smilies/headbonk.gif b/smilies/headbonk.gif deleted file mode 100644 index 8767d0f..0000000 Binary files a/smilies/headbonk.gif and /dev/null differ diff --git a/smilies/headbonk.png b/smilies/headbonk.png deleted file mode 100644 index ac67711..0000000 Binary files a/smilies/headbonk.png and /dev/null differ diff --git a/smilies/honk.png b/smilies/honk.png deleted file mode 100644 index e22e8ca..0000000 Binary files a/smilies/honk.png and /dev/null differ diff --git a/smilies/jadespritehead.gif b/smilies/jadespritehead.gif deleted file mode 100644 index bb28391..0000000 Binary files a/smilies/jadespritehead.gif and /dev/null differ diff --git a/smilies/jadespritehead.png b/smilies/jadespritehead.png deleted file mode 100644 index c4a5fce..0000000 Binary files a/smilies/jadespritehead.png and /dev/null differ diff --git a/smilies/lilcal.png b/smilies/lilcal.png deleted file mode 100644 index c418532..0000000 Binary files a/smilies/lilcal.png and /dev/null differ diff --git a/smilies/manipulative.png b/smilies/manipulative.png deleted file mode 100644 index d686bbc..0000000 Binary files a/smilies/manipulative.png and /dev/null differ diff --git a/smilies/mirthful.png b/smilies/mirthful.png deleted file mode 100644 index e7d54fe..0000000 Binary files a/smilies/mirthful.png and /dev/null differ diff --git a/smilies/mspa_face.png b/smilies/mspa_face.png deleted file mode 100644 index 1629678..0000000 Binary files a/smilies/mspa_face.png and /dev/null differ diff --git a/smilies/mspa_reader.gif b/smilies/mspa_reader.gif deleted file mode 100644 index 217fb43..0000000 Binary files a/smilies/mspa_reader.gif and /dev/null differ diff --git a/smilies/mspa_reader.png b/smilies/mspa_reader.png deleted file mode 100644 index 86730e2..0000000 Binary files a/smilies/mspa_reader.png and /dev/null differ diff --git a/smilies/olliesouty.gif b/smilies/olliesouty.gif deleted file mode 100644 index 44ad0ed..0000000 Binary files a/smilies/olliesouty.gif and /dev/null differ diff --git a/smilies/pc_amazed.png b/smilies/pc_amazed.png deleted file mode 100644 index 96563ae..0000000 Binary files a/smilies/pc_amazed.png and /dev/null differ diff --git a/smilies/pc_amazedfirman.png b/smilies/pc_amazedfirman.png deleted file mode 100644 index 4286405..0000000 Binary files a/smilies/pc_amazedfirman.png and /dev/null differ diff --git a/smilies/pc_bemused.png b/smilies/pc_bemused.png deleted file mode 100644 index 68d63e5..0000000 Binary files a/smilies/pc_bemused.png and /dev/null differ diff --git a/smilies/pc_chummy.png b/smilies/pc_chummy.png deleted file mode 100644 index 1f2724f..0000000 Binary files a/smilies/pc_chummy.png and /dev/null differ diff --git a/smilies/pc_distraught.png b/smilies/pc_distraught.png deleted file mode 100644 index f9126bc..0000000 Binary files a/smilies/pc_distraught.png and /dev/null differ diff --git a/smilies/pc_distraughtfirman.png b/smilies/pc_distraughtfirman.png deleted file mode 100644 index 409b308..0000000 Binary files a/smilies/pc_distraughtfirman.png and /dev/null differ diff --git a/smilies/pc_insolent.png b/smilies/pc_insolent.png deleted file mode 100644 index 0785670..0000000 Binary files a/smilies/pc_insolent.png and /dev/null differ diff --git a/smilies/pc_mystified.png b/smilies/pc_mystified.png deleted file mode 100644 index af0b859..0000000 Binary files a/smilies/pc_mystified.png and /dev/null differ diff --git a/smilies/pc_pleasant.png b/smilies/pc_pleasant.png deleted file mode 100644 index 7f41490..0000000 Binary files a/smilies/pc_pleasant.png and /dev/null differ diff --git a/smilies/pc_pranky.png b/smilies/pc_pranky.png deleted file mode 100644 index bf26cd1..0000000 Binary files a/smilies/pc_pranky.png and /dev/null differ diff --git a/smilies/pc_rancorous.png b/smilies/pc_rancorous.png deleted file mode 100644 index 9da5b9f..0000000 Binary files a/smilies/pc_rancorous.png and /dev/null differ diff --git a/smilies/pc_tense.png b/smilies/pc_tense.png deleted file mode 100644 index 63b34e8..0000000 Binary files a/smilies/pc_tense.png and /dev/null differ diff --git a/smilies/pccool.png b/smilies/pccool.png deleted file mode 100644 index b4a15b3..0000000 Binary files a/smilies/pccool.png and /dev/null differ diff --git a/smilies/pckitty.png b/smilies/pckitty.png deleted file mode 100644 index 6663bbe..0000000 Binary files a/smilies/pckitty.png and /dev/null differ diff --git a/smilies/pcstrider.png b/smilies/pcstrider.png deleted file mode 100644 index 72d9f8f..0000000 Binary files a/smilies/pcstrider.png and /dev/null differ diff --git a/smilies/perky.png b/smilies/perky.png deleted file mode 100644 index 608ec74..0000000 Binary files a/smilies/perky.png and /dev/null differ diff --git a/smilies/poolballL.gif b/smilies/poolballL.gif deleted file mode 100644 index 1c7be73..0000000 Binary files a/smilies/poolballL.gif and /dev/null differ diff --git a/smilies/poolballS.gif b/smilies/poolballS.gif deleted file mode 100644 index 6db6ad7..0000000 Binary files a/smilies/poolballS.gif and /dev/null differ diff --git a/smilies/record.gif b/smilies/record.gif deleted file mode 100644 index b32c29d..0000000 Binary files a/smilies/record.gif and /dev/null differ diff --git a/smilies/record.png b/smilies/record.png deleted file mode 100644 index d668c3e..0000000 Binary files a/smilies/record.png and /dev/null differ diff --git a/smilies/relaxed.png b/smilies/relaxed.png deleted file mode 100644 index caf9e6f..0000000 Binary files a/smilies/relaxed.png and /dev/null differ diff --git a/smilies/saw.gif b/smilies/saw.gif deleted file mode 100644 index a538325..0000000 Binary files a/smilies/saw.gif and /dev/null differ diff --git a/smilies/scorpio.gif b/smilies/scorpio.gif deleted file mode 100644 index e6bf7c6..0000000 Binary files a/smilies/scorpio.gif and /dev/null differ diff --git a/smilies/shades.png b/smilies/shades.png deleted file mode 100644 index 6441cee..0000000 Binary files a/smilies/shades.png and /dev/null differ diff --git a/smilies/sleek.png b/smilies/sleek.png deleted file mode 100644 index fa4311f..0000000 Binary files a/smilies/sleek.png and /dev/null differ diff --git a/smilies/slimer.gif b/smilies/slimer.gif deleted file mode 100644 index 1b9b48d..0000000 Binary files a/smilies/slimer.gif and /dev/null differ diff --git a/smilies/slimer.png b/smilies/slimer.png deleted file mode 100644 index aedb2ba..0000000 Binary files a/smilies/slimer.png and /dev/null differ diff --git a/smilies/squiddle.gif b/smilies/squiddle.gif deleted file mode 100644 index 2a9c1c3..0000000 Binary files a/smilies/squiddle.gif and /dev/null differ diff --git a/smilies/squiddle.png b/smilies/squiddle.png deleted file mode 100644 index 9f16866..0000000 Binary files a/smilies/squiddle.png and /dev/null differ diff --git a/smilies/tab.gif b/smilies/tab.gif deleted file mode 100644 index d2e729b..0000000 Binary files a/smilies/tab.gif and /dev/null differ diff --git a/smilies/tab.png b/smilies/tab.png deleted file mode 100644 index 6f5fa7a..0000000 Binary files a/smilies/tab.png and /dev/null differ diff --git a/smilies/theprofessor.png b/smilies/theprofessor.png deleted file mode 100644 index 9a7b6ed..0000000 Binary files a/smilies/theprofessor.png and /dev/null differ diff --git a/smilies/trollbro.png b/smilies/trollbro.png deleted file mode 100644 index 75b6b21..0000000 Binary files a/smilies/trollbro.png and /dev/null differ diff --git a/smilies/trollc00l.gif b/smilies/trollc00l.gif deleted file mode 100644 index 39e1674..0000000 Binary files a/smilies/trollc00l.gif and /dev/null differ diff --git a/smilies/trollcool.png b/smilies/trollcool.png deleted file mode 100644 index 76dc247..0000000 Binary files a/smilies/trollcool.png and /dev/null differ diff --git a/smilies/vigorous.png b/smilies/vigorous.png deleted file mode 100644 index 382e23a..0000000 Binary files a/smilies/vigorous.png and /dev/null differ diff --git a/smilies/weasel.gif b/smilies/weasel.gif deleted file mode 100644 index 203157a..0000000 Binary files a/smilies/weasel.gif and /dev/null differ diff --git a/smilies/weasel.png b/smilies/weasel.png deleted file mode 100644 index aec489d..0000000 Binary files a/smilies/weasel.png and /dev/null differ diff --git a/smilies/what.png b/smilies/what.png deleted file mode 100644 index f632afd..0000000 Binary files a/smilies/what.png and /dev/null differ diff --git a/smilies/whatdidyoudo.gif b/smilies/whatdidyoudo.gif deleted file mode 100644 index 7fac68a..0000000 Binary files a/smilies/whatdidyoudo.gif and /dev/null differ diff --git a/smilies/whatpumpkin.png b/smilies/whatpumpkin.png deleted file mode 100644 index 57d1275..0000000 Binary files a/smilies/whatpumpkin.png and /dev/null differ diff --git a/themes.txt b/themes.txt deleted file mode 100644 index 376ed97..0000000 --- a/themes.txt +++ /dev/null @@ -1,474 +0,0 @@ -HOW TO MAKE YOUR OWN THEMES: - -Pesterchum 3.14 themes are very flexible and allow you to create -almost any kind of main window you can imagine (notable exception -being animation). This document should help you make your own themes -or make adjustments to existing themes! - -Try following along with existing themes -- it'll make this document -much less confusing! - -A note on editing existing themes: Don't edit current themes! If you -make changes in the existing themes directory, they *will* be -overwritten when you install any updates. - -CREATING A THEME ----------------- -Every theme is just a separate directory in the "themes" -directory. That directory contains all the images used in that theme -as well as a "style.js" file which is the configuration file for the -theme. - -FORMAT ------- -The theme file is unlike most configuration files. It uses a format -called JSON, which at its core looks like this: - -{"option": "value", "option2": 5, "category": {"option1": [10, 50] } } - -The idea is that it's basically a list of: "name": "value" -separated by commas, inside brackets. So to give another example: - -{"color": "red", "size": 50 } - -means "color" is "red, and "size" is 50. Note that strings should have -quotes around them and numbers should not. You can also make certain -values into categories by making the value a bracketed list, like so: - -{"memos": {"color": "red", "size": 50}, "convos": {"color": "green", "size": 50 } } - -This creates two categories: memos and convos, each with their own -color and size value. Also note that spaces don't really matter. It -helps to indent each category: - -{"memos": {"color": "red", "size": 50"}, - "convos": {"color": "green", "size": 50" } -} - -or even - -{"memos": {"color": "red", - "size": 50" }, - "convos": {"color": "green", - "size": 50" } -} - -SETTINGS --------- - -INHERITS: You can make writing themes easier on yourself by using the -"inherits" setting. This sets all the settings to be the same as the -inherited theme unless you change it. So you only need to set the -settings you want to change! - -When specifying file locations, you use the term "$path" to represent -the path to the current theme. The program will automatically -subtitute the correct location. - -A note about styles: - -PC3.14 uses Qt's Stylesheets. That means that there are several -options in the style file that use CSS-like options. Most CSS options -are actually available in these settings. See this page for details -about Qt's stylesheets: - -http://doc.qt.nokia.com/latest/stylesheet.html - -and here for how CSS works: - -http://www.w3schools.com/css/default.asp - -If you know CSS, note that there is no cascading or need to type in -tag names. The program does this for you. - -CSS values are like this: - -background:#000000; font: bold; - -with name:value; separated by ";". - -NOTE that if you change a style from a theme you inherited, you MUST -put in all the options the old style had if you want to keep them! - -I'll go over some of the most commonly used options in styles: - -background-color: Self-explanatory. A note, though: colors can be -color names ("black"), standard HTML colors ("#000000") or rgba -(red, green, blue, alpha) values ("rgba(0, 34, 151, 75%)"). - -background-image: Sets the background image to be this image. You -specify the location of the image by using "url(location)". So it -could be: "url($path/background.png)". - -background-repeat: Sets how the background should repeat if the area -is larger than the image. Values are repeat-x, repeat-y, repeat, and -no-repeat. - -border: Sets the border of the item. Should be in the form "Xpx style -color". Example: "border: 2px solid black;" See reference for styles. - -border-top/right/left/bottom: You can specify values for individual -borders the same way by using these. Example: "border-right: 1px solid -#ffff00;" - -border-image: This one is complicated. Basically it's a good way of -having a resizable image with borders. See this page for a good -tutorial: http://www.lrbabe.com/sdoms/borderImage/ - -border-radius: Set this to a certain pixel length to get a rounded -border. Example: "border-radius: 4px;" - -color: The color to make text. Example: "color: #ff0000;" - -font: A shortcut. You can specify most different font properties from -this setting. Read on... - -font-family: A string representing the font name. Be careful as -everyone's computer may not have the same fonts! Popular fonts like -"Arial" are fine. Example: "font-family: 'Arial';" Don't forget the -quotes! - -font-size: A font's size in pixels. Example: "font-size: 12px;" - -font-style: Basically italic or not. Example: "font-style: italic;" - -font-weight: Basically bold or not. Example: "font-weight: bold;" - -margin: Sets the amount of space between this object and other -objects. This is really only useful in memo and conversation -settings. You can set individual margins for right/left/top/bottom -by margin-top/left/right/bottom. Examples: "margin-top: 15px;" "margin: -5px;" - -max/min-height/width: Sets the maximum/minimum height/width for something. - -padding: Same thing as margin, kinda... basically this sets the space -between the outside of the box and the stuff inside it. See -http://doc.qt.nokia.com/latest/stylesheet-customizing.html#the-box-model -for more detail. - -selection-color: The color of the text when an item is -selected. Example: "selection-color: black;" - -selection-background-color: The color of the background of an item -when it is selected. Example: "selection-background-color: white;" - -text-align: Centers, left-justifies, and right-justifies -text. Example: "text-align: center;" - --------- - -A note about sizes and coordinates: - -Wherever it says "size", Pesterchum expects a value of the form [width, -height], where width and height are NUMBERS. No quotes should be -involved. Example: - -"size": [232,280] - -Same with coordinates, and with coordinates, they are always the -distance away from the top left corner. So [50, 60] would be 50 pixels -to the right and 60 pixels down. - - -OK, onto the main event: - -MAIN ----- - -"main": { .... } - -This is the section that controls the main chum window. - -"style": Sets the style of the main window (as above). This value will -affect other parts of the window. DO NOT put a background image -here. You must set that separately; this is necessary to support -themes that are not square (e.g. gold xl). - -"background-image": Sets the background image. This will define the -shape of your pesterchum! This is your canvas! See the included themes -for examples of what background images look like. - -"size": The size of the window. Usually this is the same as the size -of your background image. - -"icon": The file name of the image you want to appear in the tray and -your taskbar. Example: "icon": "$path/trayicon.png" - -"newmsgicon": The file name of the image that will appear in the tray -when you have a new message. - -"windowtitle": The title of the window. - -"close": Category: - "image": Location of the image of the "X" button. - "loc": The coordinates of the "X" button. -Example: -"close": {"image": "$path/x.png", "loc": [210,2]} - -"minimize": Category. Same as "close" but for the minimize button. - -"menubar": Category. Contains one element: - "style": Style of the main menubar. - -"menu": Category. - "style": Style of each individual menu. - "menuitem": Affects each menu item on the main menu. Usually used - for spacing. - "selected": Style information for when you hover over a menu option. - "loc": Location of the main menubar. - -"sounds": Category. - "alertsound": Path to the alert sound. Should be a wav. - "ceasesound": Path to the sound when people cease pestering. - -"menus": Category. This is where you change the text of the menus. - "client": Category. The client menu. - "_name": The text for the client menu header. - (These are self explanatory:) - "options" - "memos" - "userlist" - "import" - "reconnect" - "idle" - "exit" - "profile": Category. Profile menu. - "_name": Text of the profile menu header. - "switch" - "color" - "theme" - "block" - "quirks" - "help": Category. Help menu. - "_name": Text of the help menu header - "about" - "rclickchumlist": Category. Text for right click menus. - "pester" - "removechum" - "blockchum" - "addchum" - "unblockchum" - "banuser" - "opuser" - "quirksoff" - -"chums": Category. Creates your chumroll, where all the users are. All -of them. - - "style": Style for the chumroll - "loc": Location of the chumroll - "size": Size of the chumroll - "userlistcolor": Default text color of the users - "moods": Category. Contains a list of mood icons and colors; when a - user has that mood, their handle will appear with that icon and text - color. Basically follows the form "mood": { "icon": "$path/file.png", "color": "colorname" } - Moods are: - "chummy", "rancorous", "offline", "pleasant", "distraught", - "pranky", "smooth", "mystified", "amazed", "insolent", "bemused", - "ecstatic", "relaxed", "discontent", "devious", "sleek", - "detestful", "mirthful", "manipulative", "vigorous", "perky", - "acceptant", "protective", "blocked" - (Note: blocked is not technically a "mood", but the icon is used - when you block someone.) - - "trollslum": Category. The settings for the trollslum. - "style": Style for the trollslum. - "size": Size of the window. - "label": Category. Sets the label of the trollslum. - "style": Style of the label. - "text": The text displayed. - "chumroll": Category. - "style": Sets the style for the list of users. - - "mychumhandle": Category. Settings for the text label, the user's - current handle, and color swatch. - "label": Category. - "text": Text of label indicating chumhandle. - "loc": Location of label. - "style": Style of label. - "handle": Category. User's current handle. - "style": Style of handle. - "loc": Location of handle. - "size": Size of handle. - "colorswatch": Category. Color swatch. - "loc": Location of swatch. - "size": Size of swatch. - "text": Text displayed inside swatch. - "currentmood": Location of icon of user's current mood. - - "defaultwindow": Category. - "style": Style of the default window. (Quirks, profile changer, - etc) - - "addchum": Category. Add chum button. - "style": Style of button. - "pressed": Style of button when pressed down. - "loc": Location of button. - "size": Size of button. - "text": Text of button. - The same attributes apply for these categories: - "pester": Button to pester selected user. - "block": Button to block selected user. - - "defaultmood": Default mood of this theme. - "moodlabel": Category. Text label indicating mood buttons. - "style": Style of label. - "loc": Location of label. - "text": Text of label. - - "moods": OK this can get complicated. Basically this is a list of - categories, one for each mood button present in the interface. You - make a list like this example: - -"moods": [{"style": "", "option": "value"}, {"style": "", "option": "value"}] - - The square brackets are important! - Anyway, for each mood, here are the possible settings: - "style": Style of the mood button. - "selected": Style of the mood button when selected. - "loc": Location of the mood button. - "size": Size of the mood button. - "text": Text displayed on the mood button. - "icon": Path to icon displayed on the mood button. - "mood": Mood # of the button. See mood numbers -> mood names index - at the end of this document. - -CONVO SECTION -------------- - -{"main": { ... }, - "convo": { ... } - -This controls the conversation windows. - - "style": Style of the conversation window. Only affects the main - window; does not cascade to the other parts. - "scrollbar": Category. This item is OPTIONAL. It can be a little - complicated: if you add this item, you MUST specify ALL of the - settings yourself. If you don't add this item, it will use default - system scrollbars. If you are inheriting a theme that does have - scrollbar customization and you want to remove it, enter "scrollbar: null". - - Anyway, onto the scrollbar options: - "style": General style of whole scrollbar. - "handle": Style for the handle of the scrollbar. - "downarrow": Style for the down arrow. - "darrowstyle": Generally this is where you set the image of the - down arrow with "image:url($path/downarrow.png)". - "uparrow": Same as down arrow. - "uarrowstyle": Same as darrowstyle but for up arrow. - - "margins": Category. Sets the margins around the contents of the - conversation window. - "top": Top margin - "bottom", "left", "right" - - "size": Initial size of the conversation window. - "chumlabel": Category. The part that says who youre chatting with. - "style": Style for the chumlabel. - "align": Category. - "h": Horizontal alignment - "v": Vertical alignment - "minheight": The minimum height the chum label can be. - "maxheight": The tallest the chum label can be. - "text": The text of the label. Use $handle to represent the name - of the person you're talking to. Example: ":: $handle ::" - - "textarea": Category. The window with the pesterlog in it. - "style": Style of the window. - - "input": Category. The place where you type. - "style": Style of the input area. - - "tabwindow": Category. The window that holds the tabs. - "style": Style of the window. - - "tabs": Category. Style of the tabs in tabbed conversation. - "style": Style of the tabs. - "selectedstyle": Style of the currently selected tabs. - "newmsgcolor": The color the text should turn when you get a new - msg. - "tabstyle": Usually 0. See the Qt Stylesheets for more - information. - - "text": Category. Flavor text for system messages. In the following - examples, the text in all caps will be replaced with these values: - "beganpester": " BEGAN PESTERING at